Modüller ve Kütüphaneler

Kodu dosyalara ayırmak, hazır ve dış kütüphaneleri kullanmak

Dr. Öğr. Üyesi Oğuz Emre Kural

Bir İşlevi İki Programda Kullanmak

Geçen derste bir sözlükteki notlardan ortalama hesapladık. Şimdi aynı hesaba hem öğretmenin kullandığı programda hem de dönem sonu raporunda ihtiyaç duyduğumuzu düşünelim. İşlevi iki dosyaya kopyalarsak bir düzeltmeyi de iki yerde yapmamız gerekir.

Kodun Yeri

Ortalama hesabını tek bir dosyada tutup iki programdan kullanabiliriz. Bu dosya, diğer programların içe aktarabileceği bir modül olur.

not_hesabi.py      # Ortak hesaplama işlevleri
ogretmen.py        # not_hesabi.py dosyasını kullanır
donem_raporu.py    # Aynı dosyayı kullanır
Kopyalayınca
ogretmen.pyortalama() donem_raporu.pyortalama()
Bir düzeltme iki yerde yapılır.
Modül olunca
ogretmen.py donem_raporu.py
↓ import not_hesabi.pyortalama()
Düzeltme tek yerde kalır.

Burada amaç dosya sayısını artırmak değil, aynı davranışın tek yerde tanımlanmasını sağlamaktır.

Bu Bölümde

  • import ile hazır modülleri ve kendi yazdığımız modülleri kullanacağız.
  • İçe aktarılan adların hangi dosyaya ait olduğunu takip edeceğiz.
  • Modülün içe aktarılırken neden kod çalıştırabildiğini göreceğiz.
  • Standart kütüphaneden farklı amaçlara hizmet eden modülleri kullanıp belgelerini araştıracağız.
  • Birden fazla modülü paket altında düzenleyeceğiz.
  • Üçüncü taraf bir paketi projeye ekleyecek ve yerel programda kullanacağız.

Hazır Modüller

Python’ın standart kütüphanesi, sık kullanılan işler için modüller sağlar. math matematiksel işlemleri, statistics ise sayıların ortalama ve medyan gibi özetlerini hesaplar. Bunları kullanmak için ayrıca paket kurmamız gerekmez.

Modülü İçe Aktarma

import math ifadesi math adını programımıza ekler. Modüldeki işlevi çağırırken adını önde yazarız. math.ceil() yazımı, işlevin hangi modülden geldiğini gösterir.

ceil() sonucu üst tam sayıya yuvarlar. Üç araç yalnızca 24 kişiyi taşıyacağı için 26 kişiye dördüncü araç gerekir. Aynı modülde floor() aşağı yuvarlar. math.pi ise bir işlev değil sabittir; parantezsiz yazılır.

Bir Adı Doğrudan Alma

Yalnız ceil() kullanacaksak from math import ceil yazabiliriz. Bu kez işlevi math. öneki olmadan çağırırız. İki yazım aynı hesabı yapar; değişen, işlev adının programımızda nasıl göründüğüdür.

Ad Alanı

import math sonrasında math.ceil yazmamızın nedeni, ceil adının math modülünün ad alanında bulunmasıdır. from math import ceil ise ceil adını kullandığımız dosyanın ad alanına ekler.

import math
print(math.sqrt(81))  # 9.0

from math import sqrt
print(sqrt(81))       # 9.0

Takma Ad

Bir modüle kısa ve anlaşılır bir ad verebiliriz. as modülün dosyasını değiştirmez; yalnızca bu programda kullanacağımız adı belirler.

Takma ad bir alışkanlık diye kullanılmamalı. math gibi kısa bir ad zaten açıksa olduğu gibi bırakmak daha okunaklıdır.

Üç biçim de modülü yükler. Değişen, dosyamızın ad alanına hangi adın eklendiğidir. Modül adını görünür tutmak, özellikle birden fazla modül kullandığımızda işlevin kaynağını izlemeyi kolaylaştırır.

Önceki Dersten Bir Örnek

Altıncı derste ürünleri döngüyle saymıştık. Standart kütüphanedeki Counter, aynı sayım işi için hazır bir araçtır. Önceki yöntemi anlamak önemlidir; hazır araç ne yaptığımızı bildiğimizde işimizi kısaltır.

Hangi İçe Aktarma Biçimi?

  • import math: Modül adını görünür tutarız ve math.ceil() yazarız.
  • from math import ceil: Yalnız ihtiyaç duyduğumuz adı alır, ceil() yazarız.
  • import statistics as stats: Modüle bu dosyada kullanacağımız başka bir ad veririz.

from math import * bütün uygun adları birden getirir. Hangi adın nereden geldiğini belirsizleştirebildiği için ders örneklerinde ve uygulama kodunda kullanmayacağız.

Kendi Modülümüz

Bir modül, Python tanımlarını ve ifadelerini içeren bir dosyadır. not_hesabi.py dosyasındaki ortalama() işlevini başka bir dosyadan içe aktaracağız. Bu bölümdeki çok dosyalı örnekleri bilgisayarınızda aynı klasöre kaydedip terminalden çalıştırın.

Ortak Hesaplama Dosyası

not_hesabi.py

def ortalama(notlar):
    if not notlar:
        return None
    return sum(notlar.values()) / len(notlar)

İşlev not sözlüğünü alır. Boş sözlükte bölme yapmaz; hesaplanacak not yoksa None döndürür.

Modülü Kullanan İlk Program

ogretmen.py dosyası, not_hesabi.py ile aynı klasördedir.

import not_hesabi

notlar = {101: 70, 102: 80, 103: 90}
sonuc = not_hesabi.ortalama(notlar)
if sonuc is not None:
    print(f"Sınıf ortalaması: {sonuc:.1f}")

Terminalde bu klasörden python ogretmen.py çalıştırdığımızda Sınıf ortalaması: 80.0 yazılır. Python modülü dosya adından bulur; import not_hesabi.py yazmayız. Boş bir sözlükte ortalama() None döndürür; None biçimlendirilemeyeceği için sonucu önce kontrol ediyoruz.

İkinci Program Aynı Modülü Kullanır

Dönem sonu raporunda da not ortalaması gerekiyor. donem_raporu.py dosyası modülden yalnız ortalama adını alır.

from not_hesabi import ortalama

donem_sonu_notlari = {101: 60, 102: 75}
print(ortalama(donem_sonu_notlari))  # 67.5

Bu yazımda not_hesabi adı değil, ortalama adı programın ad alanına gelir. Birden fazla işlev çağırdığımızda not_hesabi.ortalama() gibi yazmak, işlevlerin hangi modülden geldiğini daha açık gösterir.

Dosyalar Arasındaki İlişki

proje/
├── ogretmen.py       import not_hesabi
├── donem_raporu.py   from not_hesabi import ortalama
└── not_hesabi.py     def ortalama(...)

İki program aynı modülü içe aktarır. Hesaplamada bir düzeltme gerektiğinde yalnız not_hesabi.py dosyasını değiştiririz.

İçe Aktarma Sırasında Ne Olur?

Bir modülün dosya düzeyindeki ifadeleri ilk içe aktarmada çalışır. Bu küçük örnekte duyuru.py içindeki print() işlevi, biz başka bir işlev çağırmadan çıktı üretir.

duyuru.py

print("Duyuru modülü yüklendi")

def mesaj():
    return "Sınav pazartesi"

Aynı Modülü İki Kez İçe Aktarmak

main.py

import duyuru
import duyuru

print(duyuru.mesaj())
Duyuru modülü yüklendi
Sınav pazartesi

Normal bir Python çalışmasında ikinci import, önceden yüklenen modülü yeniden kullanır. Dosyayı değiştirdikten sonra açık kalan bir Python oturumunda eski davranışı görürseniz oturumu yeniden başlatın.

Doğrudan Çalıştırma ve __name__

Python, çalıştırdığı ana dosyada __name__ değerini "__main__" yapar. Aynı dosya modül olarak içe aktarılırsa bu değer modülün adıdır. Bu farkı, yalnız doğrudan çalıştırırken yapılacak işlemleri ayırmak için kullanırız.

not_hesabi.py

def ortalama(notlar):
    if not notlar:
        return None
    return sum(notlar.values()) / len(notlar)

if __name__ == "__main__":
    ornek = {101: 70, 102: 90}
    print(ortalama(ornek))  # 80.0

Koruyucunun Etkisi

python not_hesabi.py komutu örnek hesabı çalıştırır. ogretmen.py içinden import not_hesabi yapıldığında ise örnek çıktı görünmez; yalnız tanımlar kullanıma hazır hâle gelir.

Modülün içinde her print() için bu koruyucu gerekmez. Önemli olan, dosya içe aktarılırken istemeden rapor üretmek, kullanıcıdan girdi istemek veya program akışını başlatmamaktır.

Python Modülü Nerede Arar?

Python, modül adını arama yolundaki konumlarda bulmaya çalışır. Çalıştırılan betiğin klasörü bu konumlar arasındadır; standart kütüphane ve kurulu paketler de arama yolunda yer alır. Arama yolu kullanılan Python ortamına göre değişebilir.

Bu proje için basitleştirilmiş arama yolu:

ogretmen.py ile not_hesabi.py aynı klasörde değilse önce dosya düzenini ve çalıştırma biçimini kontrol edin. ModuleNotFoundError, çoğu zaman yanlış yazılmış bir ad veya beklenmeyen proje yerleşimiyle ilgilidir.

Ad Çakışması

Kendi dosyamıza statistics.py adını verirsek import statistics yazdığımızda Python beklediğimiz standart kütüphane modülü yerine yerel dosyayı bulabilir. Modüllere amaçlarını anlatan özgül adlar verelim: not_hesabi.py, ogrenci_raporu.py gibi.

from ... import * kullanımından kaçınmak da aynı okunabilirlik kaygısıyla ilgilidir. Kodda bir adın hangi modülden geldiğini izleyebilmeliyiz.

Standart Kütüphaneden Örnekler

Kendi modülümüzü yazıp içe aktardık. Şimdi Python ile birlikte gelen başka modüllere bakalım: rastgele seçim, tarih ve çalışma ortamı gibi farklı ihtiyaçlarda hangi modüle başvuracağımızı göreceğiz.

mathHesaplamaceil · sqrt · pi
randomRastgele seçimrandint · choice · sample
datetimeTarih ve saatdate · now · strftime
osÇalışma ortamıgetcwd · listdir · path

random: Sayı Üretme ve Seçim Yapma

random() sıfır dâhil, bir hariç aralıkta ondalık sayı üretir. Bir zar atışını randint(1, 6) ile simüle edebiliriz; bu kez iki sınır da olası sonuçlara dahildir. choice() bir diziden tek eleman seçer. shuffle() ise listeyi yerinde karıştırır ve None döndürür.

Sonuçlar her çalıştırmada değişebilir. choice() liste dışında string ve demet gibi dizilerde de çalışır: random.choice("abc"). Boş dizide eleman bulamaz; shuffle() ise değiştirilebilir bir dizi ister. Burada bir liste verdik.

random.seed(): Aynı Denemeyi Tekrarlamak

Bir algoritmayı denerken aynı rastgele sayı dizisini yeniden üretmek isteyebiliriz. Üreteci aynı başlangıç değeriyle iki kez başlatırsak, aynı çalışma içinde aynı sayı dizisini elde ederiz:

seed() sonucu daha rastgele yapmaz; deneyi tekrarlanabilir kılar. Örneklerde sık görülen 42 özel bir değer değildir, yalnızca yaygın bir gelenektir; başka bir sayı da seçebilirsiniz. Güvenlik amacıyla rastgele değer üretmek için random yerine secrets modülü gerekir.

datetime: Tarih ve Saat

date gün, ay ve yıl bilgisini; datetime bunlara ek olarak saati tutar. today() ve now() çalıştırıldığı andaki yerel zamanı okur, dolayısıyla çıktıları sabit değildir.

Bu çıktılarda saat ve tarih, kodu çalıştıran ortamın saatine bağlıdır. Gerçek bir son teslim zamanı saklayacaksak saat dilimini de ayrıca düşünmemiz gerekir; burada yalnız temel tarih ve saat kullanımını görüyoruz.

Tarihi İstenen Biçimde Yazmak

Bir raporun tarihini 05.11.2026 biçiminde göstermek istiyoruz. strftime() tarih nesnesinden bir string üretir. %d gün, %m ay, %Y dört basamaklı yıl anlamına gelir.

Saat için datetime.now().strftime("%H:%M") yazabiliriz. %H 24 saatlik düzende saati, %M dakikayı verir. Biçimlendirme tarih nesnesini değiştirmez.

os: Çalışma Klasörü

os.getcwd() geçerli çalışma klasörünü, os.listdir(".") bu klasördeki adları verir. os.chdir("veri") çalışma klasörünü değiştirir; bundan sonraki göreli yollar yeni klasöre göre yorumlanır.

import os

print(os.getcwd())
print(os.listdir("."))
os.chdir("veri")  # Projede veri/ klasörü varsa
print(os.getcwd())

Bu örneği kendi proje klasörünüzde deneyin. Tarayıcıdaki Python hücresi bilgisayarınızın klasörlerini değil, tarayıcıya ayrılmış dosya ortamını görür. chdir() bir modülün yerini değiştirmez; çalışan programın göreli dosya yollarını etkiler.

os.path: Yol ve Dosya Kontrolü

Proje kökünde veri/notlar.csv dosyası olduğunu varsayalım. join() yolun parçalarını işletim sistemine uygun ayraçla birleştirir. exists() yolun varlığını, isfile() dosya, isdir() klasör olup olmadığını sınar.

import os

yol = os.path.join("veri", "notlar.csv")
print(os.path.exists(yol))
print(os.path.isfile(yol))
print(os.path.isdir("veri"))
if os.path.isfile(yol):
    print(os.path.getsize(yol))  # Bayt cinsinden boyut

getsize() var olmayan bir yolda hata verir. Önce isfile() kontrolü yapmamızın nedeni budur. Yolun gerçekten hangi klasöre göre çözüleceği, geçerli çalışma klasörüne bağlıdır.

os: Klasör ve Dosya İşlemleri

mkdir() tek bir klasör oluşturur; klasör zaten varsa hata verir. makedirs() iç içe klasörleri de oluşturabilir. rename() dosyayı yeniden adlandırabilir veya başka bir klasöre taşıyabilir. remove() dosyayı, rmdir() ise boş klasörü siler.

Deneme Klasöründe Taşıma ve Silme

Bu kodu yalnızca yerel bilgisayarınızda, ayrı bir ip7_deneme klasörünün içinden çalıştırın. Başlamadan önce klasöre deneme amaçlı boş bir taslak.txt dosyası koyun; ciktilar klasörü henüz bulunmasın:

ip7_deneme/
└── taslak.txt

Örnek önce dosyayı ciktilar içine taşır, ardından dosyayı ve boşalan klasörü siler.

Deneme Dosyasını Taşıyıp Silme

import os

os.makedirs("ciktilar", exist_ok=True)
os.rename("taslak.txt", os.path.join("ciktilar", "rapor.txt"))
os.remove(os.path.join("ciktilar", "rapor.txt"))
os.rmdir("ciktilar")

exist_ok=True, ciktilar klasörü zaten varsa oluşturma hatasını önler. Ancak böyle bir klasörde önceden bulunan rapor.txt dosyası bu örnekte değiştirilebilir veya silinebilir. Bu yüzden kodu yalnız belirtilen boş deneme klasöründe çalıştırın. Silme işlemleri geri alınamayabilir. Dosya içeriğini okuma ve yazmayı sonraki derste ele alacağız.

Ortam Değişkenleri

Programın çalışma ayarları bazen ortam değişkenleriyle verilir. os.environ bunlara anahtar-değer yapısı gibi eriştirir; os.getenv(ad, varsayılan) ise aranan değişken yoksa verilen varsayılanı döndürür.

import os

print("DERS_MODU" in os.environ)
mod = os.getenv("DERS_MODU", "gelistirme")
print(mod)

Ortam değişkenleri makineden makineye değişir. os.environ içeriğinin tamamını ekrana basmak doğru değildir; erişim anahtarları gibi gizli değerler de bulunabilir.

Modülleri Keşfetmek

Her modülün işlevlerini ezberlememiz beklenmez. Önce adları bulur, sonra kullanacağımız işlevin açıklamasına bakarız.

  1. İhtiyacı söyle"Listeden iki farklı öğrenci seçmek istiyorum"
  2. Adı buldir(random)
  3. Belgeyi okuhelp(random.sample)
  4. Denerandom.sample(adlar, 2)

dir(): Modülde Hangi Adlar Var?

dir(modül) modülde tanımlı adların sıralı bir listesini verir. Listede işlevlerin yanı sıra sabitler ve __name__ gibi özel adlar da bulunabilir.

dir() bize adları gösterir; sqrt() işlevinin ne beklediğini veya ne döndürdüğünü açıklamaz. Bunun için belgeye bakmamız gerekir.

help(): İşlev Nasıl Kullanılır?

help() bir modülün ya da işlevin kullanım açıklamasını gösterir. Bir işlev seçtiğimizde parametreleri ve kısa açıklamayı okuyabiliriz:

import math

help(math.sqrt)

Bu komutu yerel Python terminalinde deneyin. Çıktı terminale ve Python sürümüne göre farklı görünebilir. help(math) bütün modülü anlattığı için daha uzun bir belge açar; sorumuz tek bir işleve aitse help(math.sqrt) daha kullanışlıdır.

random.sample() İşlevini Bulmak

Örneğin bir listeden tekrar etmeyen iki öğrenci seçmek istiyoruz. dir(random) içinde sample adını bulup help(random.sample) ile parametrelerini inceledikten sonra şu çağrıyı yazabiliriz:

sample() iki farklı konumdan seçim yapar ve yeni bir liste döndürür; adlar değişmez. Hangi öğrencilerin seçileceği çalıştırmadan çalıştırmaya değişebilir.

Paketler

Proje büyüdükçe tek modüle birbiriyle ilgisiz işlevler yığmak zorlaşır. Paket, ilişkili modülleri bir dizin altında düzenler. İçe aktarırken dizin ve modül adlarını noktayla birleştiririz.

Bir Okul Paketi

proje/
├── main.py
└── okul/
    ├── __init__.py
    ├── notlar.py
    └── ogrenciler.py

okul/notlar.py not hesaplarını, okul/ogrenciler.py öğrenci kayıtlarıyla ilgili işlevleri tutar. Başlangıç için __init__.py boş kalabilir. Bu dosyayla kurduğumuz yapı, sıradan bir Python paketidir.

İki Modülün İki Görevi

okul/notlar.py

def ortalama(notlar):
    if not notlar:
        return None
    return sum(notlar.values()) / len(notlar)

okul/ogrenciler.py

def kayit_ekle(ogrenciler, numara, ad):
    if numara in ogrenciler:
        return False
    ogrenciler[numara] = ad
    return True

Not hesabı ile öğrenci kaydı farklı işlerdir. kayit_ekle() aynı numara zaten varsa mevcut kaydı değiştirmez; yeni bir öğrenci eklediğinde True döndürür.

Paketten İçe Aktarma

Proje kökündeki main.py iki modülden birer işlev alır:

from okul.notlar import ortalama
from okul.ogrenciler import kayit_ekle

ogrenciler = {101: "Ada", 102: "Deniz"}
kayit_ekle(ogrenciler, 103, "Ece")
notlar = {101: 70, 102: 80, 103: 90}
print(ogrenciler[103])  # Ece
print(ortalama(notlar))  # 80.0

Bu örnekte okul paket, notlar ve ogrenciler modül, ortalama ile kayit_ekle ise modüllerdeki işlevlerdir. Komutu proje kökünden python main.py olarak çalıştırırız.

from okul.notlar import ortalama
okul: paket notlar: modül ortalama: işlev

Paketten içe aktarmanın başka yazımları da vardır; bunları paket düzeni dersinde karşılaştıracağız.

__init__.py Ne İşe Yarar?

__init__.py, burada kullandığımız normal paketi açıkça tanımlar. Dosya boş olsa da from okul.notlar import ortalama çalışır. İleride paketin dışarıya sunduğu adları bu dosyada düzenleyebiliriz; ilk örnekte buna ihtiyacımız yok.

Python’da __init__.py olmadan da oluşturulabilen namespace package yapıları vardır. Bu dersin çok dosyalı örnekleri normal paket düzeniyle sınırlıdır.

Modül mü, Paket mi?

  • Tek bir .py dosyasında ilişkili işlevleri topluyorsak modül yeterlidir.
  • Birden fazla modül aynı konuya aitse onları bir paket altında düzenleyebiliriz.
  • Standart kütüphane Python ile gelir; dışarıdan kurduğumuz kütüphaneler ayrı bir konudur. import yazmak tek başına eksik bir dış paketi kurmaz.

Dosya sayısını baştan artırmamıza gerek yok. Bölme kararı, kodun yeniden kullanımına ve hangi parçaların birlikte değiştiğine dayanmalı.

Üçüncü Taraf Paketler

Bir sunucudaki kaydı okuyan küçük bir program yazmak istediğimizi düşünelim. Bunu standart kütüphaneyle de yapabiliriz; ancak HTTP istekleri için kullanılan requests paketi daha kısa ve okunaklı bir çözüm sunar. Böyle bir paketi kullanmadan önce projemizin Python ortamına kurmamız gerekir. PyPI, bu paketlerin yayımlandığı çevrimiçi dizindir. import requests satırı yalnızca kurulu bir paketi yükler; kurulumu kendisi yapmaz.

Bir Paketi Projeye Eklemek: uv

Birinci derste projeye özel ortam için uv kullanmıştık. Proje kökünde uv add requests komutu, requests bağımlılığını projeye ekler ve ortamı günceller. Ardından programı aynı ortamda uv run ile çalıştırırız.

uv add requests
uv run python api_oku.py

uv add, proje bağımlılığını pyproject.toml dosyasına yazar; çözümlenen sürümleri uv.lock dosyasında tutar. Projeyi başka bilgisayarda açan kişi uv sync ile aynı bağımlılıkları kurabilir. Bu komutları tarayıcıdaki kod hücresinde değil, proje klasöründe terminalden çalıştırın.

  1. PyPIPaketlerin yayımlandığı dizin
  2. uv add requestsPaketi indirir
  3. Proje ortamı.venv/ içine kurulur; pyproject.toml ve uv.lock güncellenir
  4. import requestsProgram paketi kullanır

requests: İlk HTTP İsteği

requests standart kütüphanenin parçası değildir; önceki adımdaki uv add requests komutu tamamlanmış olmalıdır. Aşağıdaki kodu yerel api_oku.py dosyasına yazıp terminalde çalıştırın:

import requests

url = "https://jsonplaceholder.typicode.com/todos/1"
response = requests.get(url, timeout=5)
print(response.status_code)

timeout=5, sunucu yanıt vermediğinde programın süresiz beklemesini önler. HTTP durum kodu isteğin sonucunu anlamamıza yardım eder; bağlantı veya sunucu sorunu varsa kod hata verebilir. Bu örnek internet erişimi gerektirir ve tarayıcıdaki Pyodide hücresi için hazırlanmadı.

JSON Yanıtını Kullanma

Sunucu başarılı bir yanıt verdiyse response.json() ile içeriği Python değerlerine dönüştürürüz. Bu adresteki yanıt bir sözlüktür; önceki derste öğrendiğimiz anahtarla erişimi burada kullanabiliriz.

import requests

url = "https://jsonplaceholder.typicode.com/todos/1"
response = requests.get(url, timeout=5)
response.raise_for_status()
kayit = response.json()

print(kayit["title"])
print(kayit["completed"])

raise_for_status() başarısız HTTP durumunda hata üretir. json() çağrısı ise yanıtın gerçekten geçerli JSON içerdiğini varsayar; gerçek uygulamada ağ ve veri hatalarını ayrıca yönetiriz. Bu dersin amacı, dışarıdan kurduğumuz paketin programda nasıl kullanıldığını görmektir.

Bağımlılıkları Yeniden Kurmak

uv kullanan projede pyproject.toml hangi paketlerin gerektiğini, uv.lock ise seçilen kesin sürümleri kaydeder. Bu dosyaları projeyle paylaşırız; .venv/ klasörünü paylaşmayız. Yeni ortamda uv sync bağımlılıkları kurar.

Projeyle paylaşılır pyproject.toml uv.lock

Hangi paketin hangi sürümle gerektiğini kaydeder.

Paylaşılmaz .venv/

Her bilgisayar bunu uv sync ile yeniden kurar.

uv sync

Alternatif: pip ile Kurulum ve Paket Bilgisi

pip de Python paket yöneticisidir. Aşağıdaki komutları etkinleştirilmiş bir sanal ortamda çalıştırın; böylece paketi sistemdeki başka bir Python kurulumuna yanlışlıkla yüklemezsiniz. python -m pip yazımı, pipi kullandığınız Python yorumlayıcısıyla çalıştırır.

python -m pip install requests
python -m pip list
python -m pip show requests

list kurulu paketleri, show requests seçilen paketin sürümü ve kurulu olduğu konum gibi bilgileri gösterir. Paket artık gerekmiyorsa python -m pip uninstall requests ile kaldırabiliriz. Bir projede uv akışını seçtiysek bağımlılık ekleme ve kaldırmayı uv add ile uv remove üzerinden sürdürmek daha tutarlıdır.

pip Projesinde Bağımlılık Dosyası

pip ile çalışan bir projede geleneksel yol, paketleri requirements.txt dosyasında listelemektir. pip freeze etkin ortamdaki kurulu paketlerin sürümlerini de yazdığı için komutu projeye özel, temiz bir sanal ortamda kullanmak gerekir:

python -m pip freeze > requirements.txt
python -m pip install -r requirements.txt

Bu iki iş akışı aynı sorunu çözer, fakat dosyaları aynı biçimde yönetmez. uv.lock dosyasını elle düzenlemeyiz; requirements.txt ise pip akışında kurulacak sürümleri satır satır belirtir.

requirements.txt İçeriği

Basit bir projede dosya elle de yazılabilir. Her satır bir bağımlılığı belirtir. Örneğin requests>=2,<3 ifadesi, sürüm 2 ve üzerini kabul ederken 3 ve üzerini dışarıda bırakır. requests==2.32.3 gibi == ise tam olarak o sürümü ister:

# requirements.txt
requests>=2,<3

python -m pip install -r requirements.txt bu dosyadaki koşullara uygun sürümleri kurar. pip freeze ise mevcut ortamda kurulu kesin sürümleri yazar. Biri kabul edilen sürüm aralığını, diğeri o ortamın o andaki kurulu hâlini ifade edebilir; dosyanın amacını bilerek seçmeliyiz.

Kullanımda Dikkat Edilecekler

Okunur İçe Aktarmalar

  • İçe aktarmaları dosyanın başında tutmak, bağımlılıkları görmeyi kolaylaştırır.
  • Kullanılan adın kaynağı belirsizleşiyorsa modül adını önde bırakın: math.ceil() gibi.
  • Modül adını standart kütüphanedeki bir adla çakıştırmayın.
  • İçe aktarılacak dosyanın üst düzeyinde yalnız gerekli tanımlar ve hafif başlangıç işleri bulundurun.

Aynı Dosyayı İki Şekilde Kullanmak

rapor.py dosyasını iki şekilde kullanabiliriz:

  • Başka bir dosya import rapor yazar ve içindeki işlevleri kullanır.
  • Biz terminalde python rapor.py yazar ve dosyayı doğrudan çalıştırırız.

Dosyanın sonuna işlevi denemek için bir print() satırı yazdığımızı düşünelim. Doğrudan çalıştırınca bu satırın çalışmasını isteriz. Başka bir dosya yalnızca işlevleri almak için import yaptığında ise ekrana aniden deneme çıktısı gelmesini istemeyiz.

if __name__ == "__main__": satırı bu ayrımı yapar. Altındaki satırlar yalnızca dosya doğrudan çalıştırılınca çalışır.

Bu if Ne Zaman Lazım?

  • Dosyayı hem içe aktaracak hem doğrudan çalıştıracaksak.
  • Deneme hesabı, ekrana rapor yazdırma, kullanıcıdan veri isteme gibi satırlar if altına yazılır.
  • Dosyada yalnızca işlev tanımları varsa if gerekmez.

Çok dosyalı örnekler tarayıcıdaki tek kod hücresinde aynı biçimde çalışmaz. Bunları yerel proje dosyalarına yazıp terminalden deneyin; tek dosyalı standart kütüphane alıştırmaları ise sayfada çalıştırılabilir.

Alıştırmalar

Önce hangi modüle ihtiyaç olduğunu belirleyin. Çok dosyalı sorularda her dosyanın görevini ayrı düşünün ve komutu hangi klasörden çalıştırdığınızı belirtin.

Alıştırma 1: Servis Aracı Sayısı

Bir geziye 37 öğrenci katılıyor. Bir araçta en fazla 12 öğrenci taşınabiliyor. Standart kütüphaneden uygun işlevi içe aktararak gereken araç sayısını hesaplayın. Sonuç 4 olmalı.

Alıştırma 1 · Çözüm

Çözüm

Kesirli araç kullanamayız. Bölüm sonucu tam sayı değilse math.ceil() bir üst tam sayıyı verir.

Alıştırma 2: Uç Değere Bakmak

Bir sınavdaki notlar [50, 60, 70, 80, 100]. Standart kütüphanedeki statistics modülünü kullanarak ortalama ve medyanı yazdırın. Sonra 100 yerine 200 koyup iki ölçünün nasıl değiştiğini gözlemleyin.

Alıştırma 2 · Çözüm

Çözüm

Uç değer ortalamayı yükseltti; ortadaki değer olan medyan değişmedi. Burada amaç yalnız import yazmak değil, hazır işlevin ürettiği sonucu yorumlamaktır.

Alıştırma 3: Kendi Modülün

Bir öğrenci grubunun notlarını sözlükte tutuyorsunuz. not_hesabi.py dosyasına, eşik değere ulaşan öğrenci sayısını döndüren basarili_sayisi(notlar, esik=50) işlevini yazın. main.py dosyasında modülü içe aktarın ve sonucu yazdırın. Her iki dosya aynı klasörde olsun.

notlar = {101: 40, 102: 50, 103: 75}
beklenen sonuç: 2

Alıştırma 3 · Çözüm

Örnek çözüm

not_hesabi.py

def basarili_sayisi(notlar, esik=50):
    sayac = 0
    for puan in notlar.values():
        if puan >= esik:
            sayac += 1
    return sayac

main.py

import not_hesabi

notlar = {101: 40, 102: 50, 103: 75}
print(not_hesabi.basarili_sayisi(notlar))  # 2

50 sınır değeri sayılır. Hesaplama işlevi modülde kalır; main.py veriyi sağlar ve sonucu gösterir.

Alıştırma 4: Paket Yolunu Kur

Şu proje yapısında ozet() işlevi okul/rapor.py dosyasında tanımlı. main.py içinden işlevi içe aktarıp çağıran iki satırı yazın. okul/__init__.py boş olabilir.

proje/
├── main.py
└── okul/
    ├── __init__.py
    └── rapor.py        # def ozet(): ...

Alıştırma 4 · Çözüm

Çözüm

main.py

from okul.rapor import ozet
ozet()

Komutu proje kökünden python main.py olarak çalıştırın. okul.rapor yolu, paketin ve modülün adını birlikte gösterir; .py uzantısı import ifadesinde yazılmaz.

Alıştırma 5: Tekrarlanabilir Kura

Dört öğrenciden iki kişiyi random.sample() ile seçin. Aynı seed değerini kullanarak seçimi bir kez daha yapın ve iki sonucun eşitliğini yazdırın. Kaynak öğrenci listesi değişmemeli.

Alıştırma 5 · Çözüm

Çözüm

Tohum değerini iki seçimden önce de ayarladığımız için sonuçlar eşittir. sample() yeni liste üretir; shuffle() kullansaydık adlar listesi değişirdi.

Alıştırma 6: Tarihli Rapor Yolu

Son teslim günü 5 Kasım 2026 olan bir raporun adını 2026-11-05.txt yapın. Dosyanın raporlar klasöründeki yolunu os.path.join() ile oluşturup yazdırın. Burada dosya oluşturmanız gerekmiyor.

Alıştırma 6 · Çözüm

Çözüm

isoformat() dosya adında kullanabileceğimiz 2026-11-05 metnini verir. Yol ayracını elle yazmadık; join() çalışılan işletim sistemine göre ekler.

Alıştırma 7: Çalışma Ortamını İncele

Yerel bilgisayarınızda küçük bir Python programı yazın. Geçerli çalışma klasörünü ve bu klasördeki yalnızca klasör adlarını yazdırın. DERS_MODU ortam değişkeni yoksa gelistirme değerini gösterin. Çıktı bilgisayarınıza göre değişecektir.

Alıştırma 7 · Çözüm

Örnek çözüm

import os

print(os.getcwd())
for ad in os.listdir("."):
    if os.path.isdir(ad):
        print(ad)
print(os.getenv("DERS_MODU", "gelistirme"))

Bu kod dosya adlarını filtreler, klasör adlarını bırakır. Program başka bir çalışma klasöründen başlatılırsa getcwd() ve listeleme sonucu değişir; bu nedenle sabit bir çıktı beklemiyoruz.

Alıştırma 8: Bilmediğin Bir İşlevi Bul

math modülünde factorial adlı işlev bulunup bulunmadığını dir() ile kontrol edin. Ardından yerel Python terminalinde help(math.factorial) açıklamasını okuyun ve 5! değerini hesaplayın.

Alıştırma 8 · Çözüm

Çözüm

import math

print("factorial" in dir(math))  # True
help(math.factorial)
print(math.factorial(5))         # 120

dir() adı bulmamızı, help() işlevin ne yaptığını ve hangi argümanı beklediğini öğrenmemizi sağlar. Ardından işlevi kullanırız.

Alıştırma 9: Dışarıdan Paket Kullan

Projenize requests ekleyin. https://jsonplaceholder.typicode.com/todos/1 adresindeki JSON kaydını alıp title ve completed alanlarını yazdıran api_oku.py dosyasını oluşturun. uv kullanıyorsanız paket ve çalıştırma komutlarını da yazın. pip kullanıyorsanız bunu etkin bir sanal ortamda yapın.

Alıştırma 9 · Çözüm

Örnek çözüm

uv projesinde terminal komutları:

uv add requests
uv run python api_oku.py

Etkin bir sanal ortamda pip kullanılıyorsa kurulum komutu python -m pip install requests olur. api_oku.py içeriği iki kurulum biçiminde de aynıdır:

import requests

response = requests.get(
    "https://jsonplaceholder.typicode.com/todos/1", timeout=5
)
response.raise_for_status()
kayit = response.json()
print(kayit["title"])
print(kayit["completed"])

Bu alıştırma internet bağlantısı ve yerel kurulum gerektirir. Bağlantı, HTTP durumu veya JSON içeriği beklenenden farklıysa kod hata verebilir; sonraki hata yönetimi bölümünde bu durumları ele alacağız.

Alıştırma 10: Koruyucuyu Yaz

not_hesabi.py dosyasında basarili_sayisi(notlar, esik=50) işlevi tanımlı. Dosyaya, yalnız doğrudan çalıştırıldığında {101: 40, 102: 75} notları için sonucu yazdıran bir örnek ekleyin. Sonra aynı klasörde yalnız import not_hesabi satırını içeren bir main.py yazın. İki komutu çalıştırıp çıktıları karşılaştırın.

python not_hesabi.py   →  1
python main.py         →  (çıktı yok)

Alıştırma 10 · Çözüm

Örnek çözüm

not_hesabi.py

def basarili_sayisi(notlar, esik=50):
    sayac = 0
    for puan in notlar.values():
        if puan >= esik:
            sayac += 1
    return sayac

if __name__ == "__main__":
    print(basarili_sayisi({101: 40, 102: 75}))  # 1

main.py

import not_hesabi

python not_hesabi.py çalıştığında __name__ değeri "__main__" olur ve örnek yazdırılır. main.py modülü içe aktarırken __name__ değeri "not_hesabi" olduğu için koşul sağlanmaz; yalnız işlev tanımlanır.

Kendini Sına

Önce cevabı gerekçesiyle tahmin edin. Kod sorularında hangi adın hangi dosyanın ad alanında bulunduğunu özellikle kontrol edin.

Soru 1

import math
print(ceil(2.2))
  • A. 2
  • B. 3
  • C. NameError
  • D. ImportError
  • E. None

Soru 1 · Cevap

C. import math, ceil adını doğrudan eklemez. math.ceil(2.2) yazarsak sonuç 3 olur.

Soru 2

Bir öğrenci projesinde not hesapları, öğrenci kayıtları ve rapor işlevleri ayrı ayrı büyüyor. Hangi düzen bu kod için en uygundur?

  • A. Hepsini tek büyük .py dosyasında tutmak
  • B. Her işlevi ilgili programlara kopyalamak
  • C. İlişkili işlevleri ayrı modüllere bölüp okul gibi bir paket altında toplamak
  • D. Her modülden from modul import * ile bütün adları almak
  • E. __init__.py dosyasına bütün işlevleri yazıp modülleri silmek

Soru 2 · Cevap

C. İlişkili modülleri paket altında topluyoruz; her dosyanın görevi belli kalıyor.

Soru 3

duyuru.py dosyasının ilk satırı print("Yüklendi"). main.py aşağıdaki kodu içeriyor:

import duyuru
import duyuru

Normal bir Python çalışmasında kaç kez Yüklendi yazılır?

  • A. Hiç
  • B. Bir kez
  • C. İki kez
  • D. Sonsuz kez
  • E. SyntaxError oluşur

Soru 3 · Cevap

B. Dosya düzeyindeki ifade ilk içe aktarmada çalışır. İkinci import yüklenmiş modülü kullanır.

Soru 4

rapor.py içindeki aşağıdaki print() ne zaman çalışır?

if __name__ == "__main__":
    print("Rapor hazır")
  • A. Yalnız import rapor sırasında
  • B. Dosya doğrudan çalıştırıldığında
  • C. Her import sırasında
  • D. Hiçbir zaman
  • E. Yalnız paket içindeyken

Soru 4 · Cevap

B. Dosya ana program olarak çalıştırıldığında __name__ değeri "__main__" olur; içe aktarılırken bu koşul sağlanmaz.

Soru 5

okul/notlar.py dosyasında ortalama() işlevi var. Proje kökündeki main.py için doğru içe aktarma hangisidir?

  • A. import okul/notlar.py
  • B. from okul.notlar import ortalama
  • C. from okul.py import notlar
  • D. import ortalama from okul.notlar
  • E. from okul/notlar import ortalama

Soru 5 · Cevap

B. Paket ve modül adlarını noktayla ayırırız. İçe aktarma ifadesinde yol ayracı veya .py uzantısı kullanmayız.

Soru 6

random modülünde sample adlı işlevin bulunup bulunmadığını ve hangi argümanları aldığını araştırmak için hangi sıra uygundur?

  • A. Önce dir(random), sonra help(random.sample)
  • B. Önce help(random), sonra import sample
  • C. Önce random.sample(), sonra dir(sample)
  • D. Yalnız print(random)
  • E. Yalnız import random.sample

Soru 6 · Cevap

A. dir(random) adı bulmamıza, help(random.sample) kullanımını öğrenmemize yardım eder.

Soru 7

Yeni bir uv projesinde import requests satırı ModuleNotFoundError üretiyor. requests henüz proje bağımlılığı değil. İlk yapılacak işlem hangisi?

  • A. requests.py adlı boş dosya açmak
  • B. uv add requests çalıştırmak
  • C. Yalnız uv sync çalıştırmak
  • D. from requests import * yazmak
  • E. import satırını iki kez çalıştırmak

Soru 7 · Cevap

B. Önce uv add requests ile bağımlılığı projeye ekleriz; sonra programı proje ortamında çalıştırırız.

Kod Yazma: Modüle Ayırma

Aşağıdaki işlev hem main.py hem de deneme.py içinde kopya olarak bulunuyor. İşlevi not_hesabi.py dosyasına taşıyın. İki programda da işlevi aynı modülden çağıracak import satırını ve çağrıyı yazın. İşlevin davranışı değişmemeli.

def en_yuksek_not(notlar):
    if not notlar:
        return None
    return max(notlar.values())

Kod Yazma · Çözüm

İşlev not_hesabi.py içinde bir kez tanımlanır. İki program da import not_hesabi yazar ve not_hesabi.en_yuksek_not(notlar) çağırır.

Özet ve Kazanımlar

Modüller: Kısa Özet

  • Modül: Python tanımlarını ve ifadelerini içeren dosyadır. import modul ile alınır; adlarına modul.islev() biçiminde erişilir.
  • İçe aktarma: from modul import ad yalnız belirtilen adı doğrudan kullanıma açar. as yerel bir takma ad verir.
  • Standart kütüphane: math, statistics, collections, random, datetime ve os gibi modüller Python ile gelir.
  • Doğrudan çalıştırma: if __name__ == "__main__": altındaki kod, dosya ana program olarak çalıştırıldığında yürür.

Paketler ve Kullanım İlkeleri

  • Paket: İlişkili modülleri bir dizinde toplar. okul.notlar ifadesinde okul paket, notlar modüldür.
  • Yerleşim: Bu dersteki örnek paket boş bir __init__.py dosyası kullanır. Programı proje kökünden çalıştırırız.
  • Okunabilirlik: Özgül dosya adları seçer, import * kullanımından kaçınır, modülü içe aktarırken istenmeyen işler başlatmayız.

Keşif ve Dış Paketler

  • Keşif: dir(modül) mevcut adları gösterir; help(modül.işlev) kullanım açıklamasını açar.
  • Üçüncü taraf paket: PyPI’dan gelen requests gibi bir paket, import edilmeden önce proje ortamına kurulmalıdır.
  • Bağımlılık: uv add projeye bağımlılık ekleyip pyproject.toml ve uv.lock dosyalarını günceller. pip akışında paketler requirements.txt ile taşınabilir.