Modül/paket düzeni ve temel tip ipuçları

Öğrenirken birkaç sınıfı tek dosyaya yazmak iş görür. Kod büyüdükçe her işi ayrı bir dosyaya taşımak gerekir. Bu hafta küçük bir OOP sistemini modüllere (her biri bir .py dosyası) ve bu modülleri bir arada tutan bir pakete (klasöre) böleceğiz. Tip ipucu (type hint) ile de bir fonksiyonun hangi türde değer aldığını ve döndürdüğünü imzasına yazacağız.

Çok dosyalı bir Python kod tabanında paket, modül ve sorumluluk ayrımını gösteren diyagram.

Paket ve modül yapısı
ImportantPython sürümünü önce kontrol edin

Bu bölümde kullandığımız:

  • list[str] / dict[str, Product] biçimi Python 3.9+,
  • Product | None biçimi Python 3.10+ gerektirir.

Bu derste en az Python 3.10 gerekir; mümkünse desteği süren 3.11+ bir sürüm kullanın. 1. haftada kurduğunuz sürümü terminalde yeniden kontrol edin:

# Windows
py --version

# macOS / Linux
python3 --version

Yanlış yorumlayıcı seçiliyse VS Code’da Python: Select Interpreter komutunu kullanın.

Bu bölümün kapsamı

NoteSınavda sorulur
  • Basit paket düzeni ve __init__.py dosyasının rolü
  • ModuleNotFoundError karşısında çalışma dizini denetimi
  • python app.py ile python -m paket.modul ayrımı
  • Kodu modüllere sorumluluğa göre ayırma
  • Tip ipucunun çalışma zamanında türü denetlememesi
  • T | None yazımı ve çağıranın None kontrolü
  • Sınıf ve metot imzalarındaki tip ipuçlarından nesnenin nasıl kullanılacağını okuma
  • İleri referans ve from __future__ import annotations
  • dataclass ve Enum
  • Paket yayımlama, pyproject.toml, sanal ortam yönetimi
  • mypy gibi statik tür denetleyicilerinin ayarları

Bu başlıklar konunun devamıdır; ileride karşınıza çıkar ama bu derste ezberlemeniz beklenmiyor.

Bu dosya bağımsız script olarak mı, bir paketin modülü olarak mı çalışıyor?

Bir dosyayı python app.py gibi doğrudan başlatırsanız o dosya bağımsız bir script olarak çalışır. Bir paketin içinden import ile ya da python -m ile yüklenirse o paketin modülü olarak çalışır. Aynı dosyanın import satırları, dosyayı hangi klasörden ve hangi komutla başlattığınıza göre sorunsuz da çalışabilir, ModuleNotFoundError da verebilir. Bu yüzden bu hatayı gördüğünüzde önce kurulu paketlerin listesine değil, terminalin hangi klasörde açık olduğuna bakın.

Basit paket düzeni

project/
├── app.py
└── shop/
    ├── __init__.py
    ├── product.py
    ├── customer.py
    ├── order.py
    └── errors.py

Bir klasörün Python paketi olduğunu göstermenin alışılmış ve açık yolu, içine __init__.py dosyası koymaktır. Bu dosya boş olabilir. İsterseniz içine paket ilk import edildiğinde çalışacak kodu ya da paketin dışarıya açacağı adları yazabilirsiniz. Şimdilik boş bırakmanız çoğu zaman yeterli.

Paket içindeki product.py:

from .errors import OutOfStockError

order.py:

from .product import Product

Paketin dışındaki app.py:

from shop.product import Product

Bir paketi PyPI’ya (pip install ile paket indirdiğiniz ortak depo) yükleme gibi ayrıntılar bu haftanın konusu değil. Bilmeniz gereken, bir import satırının hangi paketin içinden ve hangi çalışma dizininden çalıştığıdır.

Çalışma dizini neden önemlidir?

Çalışma dizini, terminalin o an içinde bulunduğu klasördür. Yukarıdaki yapıda en üstteki project/ klasörü proje köküdür. Terminali bu klasörde açın:

project/
├── app.py
└── shop/

Programı aynı yerden çalıştırın:

py app.py

macOS/Linux’ta:

python3 app.py

Terminal başka bir klasörde açıksa Python shop paketini aradığı yerlerde bulamayabilir ve ModuleNotFoundError görebilirsiniz.

WarningModuleNotFoundError görünce hemen paket kurmayın

Önce şunları kontrol edin:

  1. Terminal şu an hangi klasörde? (pwd; Windows PowerShell’de Get-Location)
  2. app.py ile paket klasörü gerçekten aynı proje kökü altında mı?
  3. Dosya/paket adında yazım hatası var mı?
  4. VS Code doğru klasörü mü açtı ve doğru Python yorumlayıcısını mı kullanıyor?

Kendi yazdığınız shop gibi bir paket bulunamıyorsa çözüm çoğu zaman PyPI’dan bir şey yüklemek değil, programı proje kökünden doğru biçimde çalıştırmaktır.

python app.py ile python -m package.module

Dosyanın yolunu verdiğinizde Python onu bağımsız bir script olarak başlatır:

python app.py

Bir modülü paketin parçası olarak çalıştırmak içinse şunu yazarsınız:

python -m shop.demo

-m seçeneği dosya yolu yerine modülün paket içindeki tam adını (shop.demo) alır ve modülü import satırlarının kullandığı arama düzeniyle bulup çalıştırır. Bu fark en çok göreli import’ta, yani from .product import Product gibi noktayla başlayan ve aynı paketteki bir modülü gösteren import’ta ortaya çıkar. Böyle bir modülü python shop/demo.py diye doğrudan çalıştırırsanız Python dosyanın shop paketine ait olduğunu bilmeyebilir. Proje kökünden python -m shop.demo yazarsanız modül shop paketinin parçası olarak çalışır.

Komutları ezberlemeniz gerekmiyor. Bir import hatasını teşhis ederken şu soruyu sormanız yeterli:

“Bu dosya bağımsız script olarak mı, yoksa bir paketin modülü olarak mı çalışıyor?”

Modülleri sorumluluğa göre ayırın

Kodu dosyalara ayırırken her sınıfa ayrı bir dosya açmanız gerekmez. Hangi sınıfların aynı modülde duracağına şu sorularla karar verin:

  • Bu sınıflar aynı işten mi sorumlu?
  • Bir modüldeki değişiklik başka kaç modülü etkiliyor?
  • Modülün dışındaki kod hangi adları kullanmalı?

_round_money gibi tek alt çizgiyle başlayan adlar, sınıflarda olduğu gibi modüllerde de “bu, içeride kullanılan bir yardımcıdır” anlamına gelir. Python bu adlara dışarıdan erişimi engellemez.

Tip ipucu nedir?

Python tip ipuçlarının geliştirme araçlarına bilgi verdiğini ancak çalışma zamanında tür zorlaması yapmadığını gösteren diyagram.

Tip ipucu ve çalışma zamanı

Tip ipucu, bir parametrenin ve dönüş değerinin hangi türde olması beklendiğini koda yazmanın yoludur. Yukarıda prices: list[float], fonksiyonun float değerlerden oluşan bir liste beklediğini; -> float ise bir float döndüreceğini söyler.

Tip ipucu:

  • Kodu okuyana fonksiyonun ne beklediğini söyler,
  • Editöre ve statik analiz araçlarına (kodu çalıştırmadan inceleyen mypy gibi araçlar) bilgi verir,
  • Ama varsayılan olarak Python, program çalışırken türü denetlemez.
def add(a: int, b: int) -> int:
    return a + b

print(add("a", "b"))  # type hint bunu otomatik engellemez

T | None ve eski sürüm söz dizimi

T | None, “ya T türünde bir değer ya da None” demektir; T yerine herhangi bir tür yazılır. Aranan ürün bulunamazsa None döndüren bir metodun güncel yazımı:

def find(self, code: str) -> Product | None:
    ...

Python 3.10’dan önce yazılmış kodlarda aynı şey şöyle yazılır:

from typing import Optional

def find(self, code: str) -> Optional[Product]:
    ...

Python 3.9’dan eski kaynaklarda list[str] yerine List[str], dict[str, int] yerine Dict[str, int] de görebilirsiniz. Bu derste kodu eski sürümlerde de çalışsın diye karmaşıklaştırmayacağız; güncel bir Python sürümü kullanacağız.

İleri referans (forward reference) (sınav dışı)

Bazen bir tip ipucunda, tanımı henüz tamamlanmamış bir sınıfın adını kullanmanız gerekir:

class Member:
    def choose_friend(self) -> "Member | None":
        ...

Tırnak içine yazılan tip ipucu (İngilizcesiyle annotation) sonradan çözülür. Bu kullanıma ileri referans denir. Güncel projelerde dosyanın başına şu satırı eklerseniz:

from __future__ import annotations

Python annotation’ları hemen değerlendirmez, sonraya bırakır. Böylece birçok ileri referansı tırnaksız yazabilirsiniz:

from __future__ import annotations

class Member:
    def choose_friend(self) -> Member | None:
        ...
Notefrom __future__ import annotations Python 3.10 ihtiyacını kaldırmaz

Bu satır yalnızca annotation’ların değerlendirilmesini sonraya bırakır. Python 3.9’da bu satır varken -> Member | None gibi bir imza hata vermez, çünkü annotation hiç çalıştırılmaz. Ama int | None yazımını annotation dışında, örneğin isinstance(x, int | None) içinde kullanırsanız Python 3.9 yine TypeError verir. Bu yüzden ders ortamında Python 3.10 ya da daha yeni bir sürüm gerekir.

Sınıflarda tip ipucu

Product | None, aranan ürünün bulunamayabileceğini imzada açıkça söyler. Metodu çağıran kod yine de None dönüp dönmediğini kontrol etmelidir.

ImportantTip ipucu sözleşmeyi yazar, hatayı kendiliğinden önlemez

Product | None yazmak metodun None döndürmesini engellemez. product.code satırına gelmeden önce product değerinin None olup olmadığını kontrol etmek yine programcının işidir.

Döngüsel import riski

a.py b.py’yi, b.py de a.py’yi import ederse iki modül arasında döngüsel bir bağımlılık oluşabilir. Bu bazen iki modülün işlerinin birbirine fazla karıştığını gösterir. Çözüm tekniklerine bakmadan önce kendinize şunu sorun: “Bu iki modülün gerçekten birbirini import etmesi gerekiyor mu?”

Tanımanız yeterli: dataclass ve Enum

  • dataclass: çoğunlukla veri tutan sınıflarda her seferinde elle yazdığınız __init__, __repr__ ve eşitlik kodunu azaltabilir.
  • Enum: yalnızca birkaç değer alabilen bir durumu (örneğin bir siparişin “beklemede”, “gönderildi” hâlleri) anlamlı adlarla yazmanızı sağlar.

İki yapı da sınav dışıdır; ayrıntısına girmiyoruz.

Alıştırma: Tip ipuçlarını ekle

Fonksiyonun ne aldığını ve ne döndürdüğünü dict[int, str], int ve str | None ipuçlarıyla imzaya yazın.

Alıştırma: Çalışma dizini hatasını teşhis et

project/shop/product.py ve project/app.py yapısını oluşturun. Önce proje kökünden çalıştırın. Sonra terminalde bir üst klasöre çıkıp aynı komutu deneyin. İki çalıştırma arasındaki farkı pwd/Get-Location çıktısına bakarak açıklayın. Hatayı düzeltmekle yetinmeyin; Python’ın paketi neden bulamadığını çalışma dizinine bakarak açıklayın.

Sıra sizde: Üç modüllü sistem

Yerel ortamınızda:

library-project/
├── app.py
└── library/
    ├── __init__.py
    ├── book.py
    ├── member.py
    └── library.py

oluşturun. Library.find_book(isbn) metodu Book | None döndürsün. app.py içinde kitabın bulunamadığı, yani None döndüğü durumu da ele alın.

Çalışır kod görevi: Python sürümünüzü not edin; programı proje kökünden çalıştırın; en az bir paket içi göreli import, bir paket dışı import ve bir Book | None dönüşü kullanın. Ayrıca küçük bir library/demo.py oluşturup proje kökünden python -m library.demo (Windows’ta gerekirse py -m library.demo) ile çalıştırın.

Sınav provası

Önce kendi cevabınızı seçin; sonra cevap anahtarında her şıkkın neden doğru veya yanlış olduğunu okuyun. Çeldiriciler uydurma değil, bu konuda gerçekten yapılan hatalardır. Sınav maddeleri de bu mantıkla yazılır.

Madde 1. Bir paket dizinindeki __init__.py dosyası hakkında doğru olan hangisidir?

  • A. İçi boş bırakılırsa paketteki modüller import edilemez
  • B. Yalnızca PyPI’ya yüklenecek paketlerde gerekir
  • C. Paketin bütün sınıflarını içermek zorundadır
  • D. Paketin ana giriş noktasıdır ve python paket ile çalıştırılır
  • E. Klasörü paket olarak işaretler ve boş bırakılabilir

Madde 2. Kendi yazdığınız shop paketi için ModuleNotFoundError alıyorsanız ilk olarak ne yapmalısınız?

  • A. Bütün import satırlarını try/except içine almak
  • B. pip install shop komutunu çalıştırmak
  • C. Terminalin proje kökünde açık olup olmadığını denetlemek
  • D. Python’ı kaldırıp güncel sürümle yeniden kurmak
  • E. Paketteki __init__.py dosyasını silip yeniden denemek

Madde 3. Terminalin hangi dizinde olduğunu öğrenmek için ne kullanılır?

  • A. macOS/Linux’ta pwd, PowerShell’de Get-Location
  • B. Python içinde import os ve ardından os.name
  • C. pip list ile kurulu paketleri listelemek
  • D. python --version ile yorumlayıcıyı sorgulamak
  • E. macOS/Linux’ta ls, Windows PowerShell’de dir

Madde 4. python -m shop.demo ile python shop/demo.py arasındaki fark nedir?

  • A. -m yalnız __init__.py dosyalarını çalıştırır
  • B. -m yalnızca kurulu PyPI paketleri için çalışır
  • C. -m dosyayı derleyip çalıştırır, diğeri yorumlar
  • D. İkisi tümüyle aynıdır; -m yalnız daha kısadır
  • E. -m modülü paketin bir parçası olarak çalıştırır

Madde 5. Kodu dosyalara ayırırken hangi ölçüt kullanılmalıdır?

  • A. Sınıf adlarının alfabetik sırası
  • B. Sınıfların yazılma tarihine göre gruplanması
  • C. Dosya başına en fazla 100 satır kuralı
  • D. Sınıfların aynı işten sorumlu olup olmadığı
  • E. Her sınıf mutlaka kendi dosyasında olmalıdır

Madde 6. a.py b.py’yi, b.py de a.py’yi import ediyorsa ilk sorulacak soru nedir?

  • A. “İki dosyadan hangisi önce yazıldı, hangisi ona bağlı?”
  • B. “Bu iki modülün gerçekten birbirini import etmesi gerekiyor mu?”
  • C. “Import satırlarını fonksiyon içine taşısam çözülür mü?”
  • D. “Daha yeni bir Python sürümü döngüyü kendisi çözer mi?”
  • E. “Dosyaları tek dosyada birleştirsem olur mu?”

Madde 7. Aşağıdaki program ne yazdırır?

def add(a: int, b: int) -> int:
    return a + b

print(add("a", "b"))
  • A. None
  • B. 0
  • C. ab; tip ipucu çalışma zamanında türü zorlamaz
  • D. TypeError; ipucu int dışındaki türleri reddeder
  • E. Söz dizimi hatası

Madde 8. Tip ipucu ne işe yarar?

  • A. Beklenen türü okura ve editör araçlarına bildirir
  • B. Programı daha hızlı çalıştırır
  • C. Sınıfların otomatik olarak __eq__ kazanmasını sağlar
  • D. Değerleri kendiliğinden belirtilen türe dönüştürür
  • E. Yanlış türde argüman verilmesini engeller

Madde 9. def find(self, code: str) -> Product | None: imzası çağırana ne söyler?

  • A. Metodun hiçbir zaman None döndürmeyeceğini
  • B. Çağıranın None durumunu kontrol etmesi gerektiğini
  • C. Python’ın None dönüşünde kendiliğinden hata yükselteceğini
  • D. Metodun iki değer birden döndürdüğünü
  • E. code parametresinin isteğe bağlı olduğunu

Madde 10. Bir sınıfın imzaları şöyle:

class Catalog:
    def __init__(self) -> None:
        self.products: dict[str, Product] = {}

    def add(self, product: Product) -> None: ...

    def find(self, code: str) -> Product | None: ...

Aşağıdaki kullanımlardan hangisi bu sözleşmeye uyar?

  • A. catalog.add("P1")
  • B. result = catalog.add(p) ve ardından print(result.code)
  • C. print(catalog.find("P1").price)
  • D. p = catalog.find("P1") ve ardından if p is not None: print(p.price)
  • E. catalog.find(Product("P1", 10.0))

Madde 11. Aşağıdaki imza çağırana ne söyler?

class Inventory:
    def reserve(self, code: str, amount: int) -> bool: ...
  • A. code parametresi isteğe bağlıdır
  • B. Ayrılan ürünlerin listesini döndürür
  • C. Metin kod ve tamsayı miktar alır, sonucu bool olarak bildirir
  • D. Başarısız olursa mutlaka bir istisna yükseltir
  • E. amount yerine metin verilirse Python çağrıyı çalıştırmadan reddeder

Madde 1. Doğru: E. Klasörün bir Python paketi olduğunu göstermenin alışılmış ve açık yoludur. İsterseniz içine paket ilk import edildiğinde çalışacak kodu ya da paketin dışarıya açacağı adları yazabilirsiniz. Şimdilik boş bırakmak yeterli.

  • A yanlış: Boş bir dosya işe yaramıyormuş gibi görünür. Ama boş bir __init__.py de klasörü paket olarak işaretlemeye yeter.
  • B yanlış: “Paket” sözcüğü pip install ile kurulan paketleri çağrıştırır. Ama __init__.py yerel paketlerde de kullanılır.
  • C yanlış: Dosya paketin kendisini temsil ediyormuş gibi göründüğü için paketin bütün kodunun burada toplandığı sanılabilir. Ama sınıflar ayrı modüllerde durur.
  • D yanlış: __init__ adı, kurucu gibi ilk çalışan şeyi çağrıştırır. Ama bir paketi python -m paket ile çalıştırmak için __main__.py kullanılır.

Madde 2. Doğru: C. Terminalin hangi klasörde olduğu ve app.py ile paketin aynı proje kökü altında bulunup bulunmadığı denetlenir. Kendi yazdığınız bir paket bulunamıyorsa eksik olan çoğu zaman bir kurulum değildir; program proje kökünden çalıştırılmamıştır.

  • A yanlış: Hata mesajı kaybolduğu için sorun çözülmüş gibi görünür. Ama hatayı gizler; nedeni ortadan kaldırmaz.
  • B yanlış: Hata mesajı “modül bulunamadı” dediği için eksik bir kurulum akla gelir. Ama paket sizin yazdığınızsa PyPI’da yoktur; aynı adlı yanlış bir paket kurulabilir.
  • D yanlış: Hata Python’dan geldiği için yorumlayıcının bozuk olduğu düşünülebilir. Ama yorumlayıcıyla ilgili bir sorun değildir.
  • E yanlış: Paket yapısını sadeleştirmek sorunu çözecekmiş gibi görünebilir. Ama klasörü paket olarak işaretleyen dosyayı silersiniz; sorun büyür.

Madde 3. Doğru: A. pwd ve Get-Location çalışma dizininin tam yolunu yazar. Python’ın paketleri nerede arayacağı çalışma dizinine bağlıdır; bu yüzden teşhise buradan başlanır.

  • B yanlış: os modülü dosya sistemiyle ilgili olduğu için doğru yer gibi görünür. Ama os.name işletim sistemi adını verir; çalışma dizinini değil.
  • C yanlış: Import hatası kurulumla ilgili sanıldığında bu komut akla gelir. Ama kurulu paketleri listeler; terminalin nerede olduğunu söylemez.
  • D yanlış: Sorun Python’da göründüğü için önce yorumlayıcıya bakmak akla gelir. Ama bu komut yorumlayıcı sürümünü verir; dizini değil.
  • E yanlış: Klasörün içeriğini görmek nerede olduğunuzu anlamaya yardım eder. Ama bu komutlar klasörün içindekileri listeler, klasörün tam yolunu söylemez.

Madde 4. Doğru: E. -m modülü paket içindeki tam adıyla bulup paketin parçası olarak çalıştırır; dosya yolu verildiğinde Python dosyanın hangi pakete ait olduğunu bilmeyebilir. Fark en çok göreli import kullanan modüllerde ortaya çıkar: proje kökünden -m ile çalıştırılan modül, from .product import ... satırını paketin içinden çözer.

  • A yanlış: Komutta paket adı geçtiği için yalnız paketin __init__.py dosyasının çalıştığı sanılabilir. Paket import edilirken o dosya da çalışır ama -m asıl olarak belirtilen modülü çalıştırır.
  • B yanlış: -m çoğu zaman python -m pip gibi kurulu araçlarla görüldüğü için yalnız onlara özgü sanılabilir. Ama yerel paketler için de kullanılır.
  • C yanlış: C’deki derleme ve çalıştırma ayrımı buraya taşınabilir. Ama ikisinde de Python kodu aynı biçimde çalıştırır.
  • D yanlış: Basit bir dosyada iki komut da aynı çıktıyı verdiği için aynı sanılabilir. Ama modülü farklı biçimde başlatırlar; fark göreli import’larda ortaya çıkar.

Madde 5. Doğru: D. Bir modül, aynı işle ilgili ve çoğu zaman birlikte değişen sınıfları bir arada tutar. Bir modüldeki değişikliğin kaç modülü etkilediğine de bakılır. Her sınıfa ayrı dosya açmak gerekmez.

  • A yanlış: Dosyaları bulmayı kolaylaştırdığı için düzenli görünür. Ama sıralamaya yarar, hangi sınıfların birlikte durması gerektiğini söylemez.
  • B yanlış: Proje adım adım büyüdüğü için her aşamanın kodunu ayrı tutmak akla gelebilir. Ama yazılma tarihinin sınıfların ne iş yaptığıyla ilgisi yoktur.
  • C yanlış: Kısa dosyalar okunaklı olduğu için sayıya dayalı bir kural cazip görünür. Ama satır sayısı sorumluluğu ölçmez.
  • E yanlış: Düzenli ve uygulaması kolay bir kural gibi görünür. Ama mekanik bir kuraldır; birlikte değişen sınıfları gereksizce ayırır.

Madde 6. Doğru: B. Döngüsel bağımlılık çoğu zaman iki modülün işlerinin birbirine fazla karıştığını gösterir. Çözüm tekniklerine geçmeden önce işi modüllere doğru bölüp bölmediğinize bakılmalıdır.

  • A yanlış: Bağımlılığın yazılış sırasından doğduğu sanılabilir. Ama yazım sırası bağımlılığı açıklamaz.
  • C yanlış: Bu teknik hata mesajını gerçekten ortadan kaldırdığı için çekicidir. Ama hatayı bastırır, modüllerin iş bölümünü düzeltmez.
  • D yanlış: Yeni sürümlerin eski sorunları giderdiğini gören öğrenci bunu da bekleyebilir. Ama sürümle ilgili bir sorun değildir; döngü tasarımdan gelir.
  • E yanlış: Tek dosyada döngü kalmadığı için kesin çözüm gibi görünür. Döngü kalkar ama iki modülü ayırmanın anlamı da kalmaz.

Madde 7. Doğru: C. İpucu kodu okuyana ve statik analiz araçlarına bilgi verir; yorumlayıcı çağrıyı engellemez. İki str değeri + ile toplanınca birleşir.

  • A yanlış: Fonksiyon birleştirme sonucunu döndürür.
  • B yanlış: Python bu türü kendiliğinden dönüştürmez.
  • D yanlış: Böyle bir çalışma zamanı denetimi yoktur.
  • E yanlış: Tip ipucu yazımı geçerli Python söz dizimidir.

Madde 8. Doğru: A. Tip ipucu okuyucuya niyeti gösterir, editör ve statik analiz araçlarına bilgi verir. Varsayılan olarak program çalışırken türü denetlemez; yararı, beklenen türün kodda yazılı olmasıdır.

  • B yanlış: C’de tür bildirimi derleyiciye yardım ettiği için Python’da da hız kazandıracağı sanılabilir. Ama tip ipucu yürütme hızını değiştirmez.
  • C yanlış: dataclass örneklerinde tip ipuçlarıyla birlikte __eq__ de geldiği için bu bağ kurulabilir. Ama bunu tip ipucu değil, dataclass gibi araçlar sağlar.
  • D yanlış: int(...) gibi dönüşümlere alışan öğrenci, : int yazımının da dönüştürdüğünü sanabilir. Ama dönüşüm yapılmaz.
  • E yanlış: Tür yazıldığına göre yanlış türün reddedileceği beklenir. Ama engellemez; yalnız editör ya da statik denetleyici uyarabilir.

Madde 9. Doğru: B. | None aramanın başarısız olabileceğini söyler. Tip ipucu sözleşmeyi açıkça yazar ama metodun None döndürmesini engellemez. product.code satırından önce None kontrolünü yine programcı yapar.

  • A yanlış: Dönüş türünde Product yazdığı için metodun hep ürün döndüreceği sanılabilir. Ama | None yazımı bu olasılığı açıkça bildirir.
  • C yanlış: Tür yazıldığı için Python’ın dönüşü denetleyeceği düşünülebilir. Ama böyle bir otomatik denetim yoktur.
  • D yanlış: | işareti iki türü yan yana yazdığı için iki değer dönüyormuş gibi okunabilir. Ama tek değer döner; imza bu değerin iki türden biri olabileceğini söyler.
  • E yanlış: None çoğu zaman varsayılan parametre değeri olarak görüldüğü için parametreyle ilişkilendirilebilir. Ama ipucu dönüş değerine aittir; code parametresi zorunludur.

Madde 10. Doğru: D. find bir metin kod alır ve Product ya da None döndürür. Çağıran None durumunu kontrol ettikten sonra niteliğe erişiyor.

  • A yanlış: add bir Product nesnesi bekler, ürün kodu değil.
  • B yanlış: -> None, add metodunun bir değer döndürmediğini söyler. result None olur.
  • C yanlış: Product | None aramanın başarısız olabileceğini söylüyor. Kontrolsüz erişim None geldiğinde AttributeError verir.
  • E yanlış: find bir str kod bekler. Nesnenin kendisini vermek sözleşmeye uymaz.

Madde 11. Doğru: C. Metot bir metin kod ve bir tamsayı miktar bekler; işlemin başarılı olup olmadığını True ya da False ile bildirir. Parametre ipuçları ne verileceğini, -> bool ise ne döneceğini söyler. İmza sayesinde gövdeyi okumadan metodu doğru çağırabilirsiniz.

  • A yanlış: İmzada code için ayrı bir işaret görülmediği için zorunlu olmadığı sanılabilir. Ama varsayılan değer verilmemiş; iki parametre de zorunludur.
  • B yanlış: Ayırma işi ürünlerle ilgili olduğu için metodun ürünleri döndüreceği düşünülebilir. Ama dönüş türü bool; liste dönseydi list[...] yazardı.
  • D yanlış: Önceki bölümlerde kurallar raise ile korunduğu için başarısızlığın da istisnayla bildirileceği sanılabilir. Ama imza sonucu bool olarak bildiriyor; başarısızlığın istisnayla bildirileceğini söylemez.
  • E yanlış: amount: int yazımı bir kural gibi okunabilir. Ama tip ipucu çalışma zamanında türü zorlamaz. Yanlış türü editör ya da statik denetleyici fark edebilir.

Tek sayfa özet

  • Bu ders için Python 3.10+ kullanın; sürümü ve seçili yorumlayıcıyı doğrulayın.
  • __init__.py bir klasörün paket olduğunu belirtir ve boş olabilir.
  • Import hatalarında önce çalışma dizinini, proje yapısını ve yorumlayıcıyı kontrol edin.
  • python -m bir modülü paketin parçası olarak çalıştırır.
  • Tip ipuçları sözleşmeyi gösterir ve araçlara bilgi verir; program çalışırken türü denetlemez.
  • T | None, sonucun bulunamayabileceğini imzada söyler.
  • Metot imzası sözleşmeyi söyler: ne verilir, ne döner, dönüş None olabilir mi.

Bu bölümün kazanımları

Bu bölümü bitiren öğrenci:

  • Basit bir paket düzeni kurar ve __init__.py dosyasının rolünü açıklar.
  • ModuleNotFoundError karşısında önce çalışma dizinini ve proje kökünü denetler.
  • python app.py ile python -m paket.modul arasındaki farkı açıklar.
  • Kodu modüllere sorumluluklarına göre ayırır.
  • Tip ipucunun çalışma zamanında türü denetlemediğini açıklar.
  • T | None yazımını kullanır ve çağıranın None kontrolünü hâlâ yapması gerektiğini bilir.
  • Sınıf ve metot imzalarındaki tip ipuçlarından bir nesnenin nasıl kullanılacağını okur.
Back to top