Özel metotlar ve özel istisnalar

Python’daki nesneler yalnızca bizim yazdığımız normal metotlarla değil, dilin veri modeliyle de etkileşir. print(obj), obj1 == obj2 veya hata ayıklayıcıda nesnenin görünümü gibi davranışlar özel metotlarla tanımlanabilir. Bu hafta ayrıca problem alanına özgü hataları kendi istisna sınıflarımızla ifade edeceğiz.

__str__, __eq__ ve özel istisnanın bir ürün sınıfında kullanıcıya görünen temsil, eşitlik ve alan hatası davranışlarını tanımlaması.

Bu hafta neleri yapabilmelisiniz?

  • __str__ ve __repr__ amaçlarını ayırabilmeli,
  • __eq__ ile değer eşitliği tanımlayabilmeli,
  • kimlik ile eşitlik ayrımını yeniden uygulayabilmeli,
  • eşitlik tanımının hash edilebilirlik üzerinde etkisi olabileceğini tanıyabilmeli,
  • özel istisna sınıfı tanımlayabilmeli,
  • alan kuralı ihlalini anlamlı istisnayla ifade edebilmeli,
  • istisnayı uygun katmanda yakalama fikrini açıklayabilmelisiniz.

Varsayılan nesne temsili

Varsayılan çıktı genellikle sınıf adı ve nesneyi ayırt etmeye yarayan uygulama ayrıntıları içerir. Kullanıcı veya geliştirici için çoğu zaman yeterince anlamlı değildir.

__str__: okunabilir kullanıcı temsili

print(product) artık __str__() sonucunu kullanır.

__repr__: geliştiriciye dönük temsil

İdeal repr çoğu zaman nesnenin durumunu açıkça görmeye yardımcı olur. Her durumda yeniden çalıştırılabilir Python ifadesi üretmek zorunlu değildir; bu derste öncelik hata ayıklamada açık temsildir.

__eq__: iki nesne ne zaman eşit?

Varsayılan olarak kendi sınıfımızdaki iki ayrı örnek aynı alanlara sahip olsa bile == beklediğimiz alan anlamında çalışmayabilir:

Eşitliği ürün koduna göre tanımlamak istersek:

== artık alan kuralımıza göre eşitlik sorar; is hâlâ nesne kimliğini sorar.

NoteEşitlik tasarım kararıdır

Bir Product için yalnızca code mu önemlidir? Bir Book için ISBN mi? Bir Student için öğrenci numarası mı? __eq__ yazmadan önce problem alanında “aynı kabul edilme” kuralını belirleyin.

Note__eq__ ve hash sözleşmesi

Eşitlik tanımı, nesnenin set içinde veya dict anahtarı olarak kullanılmasıyla ilişkilidir. Python veri modelinde eşit kabul edilen nesnelerin aynı hash değerine sahip olması gerekir. Bir sınıf __eq__ tanımlayıp uygun bir __hash__ tanımlamazsa örnekleri varsayılan olarak hash edilemez hâle gelir.

Bu derste __hash__ yazmıyoruz. Özellikle durumu değişebilen alan nesnelerini set elemanı veya dict anahtarı yapmadan önce eşitlik ve hash tasarımını ayrıca düşünmek gerektiğini bilmeniz yeterlidir.

Alan hatalarını özel istisnayla ifade etmek

Yerleşik ValueError birçok durumda yeterlidir. Ancak belirli bir iş kuralını çağıranın ayırt etmesi gerekiyorsa özel istisna anlamlı olabilir.

Aşağıdaki örnekte önce genel giriş kurallarını ValueError ile, alanın özel başarısızlık durumunu ise ayrı bir istisna sınıfıyla ifade ediyoruz:

Bu sürümde başarısız para çekme işlemi hesabın geçerli durumunu bozmaz. Negatif tutarın bakiyeyi yanlışlıkla artırmasına da izin verilmez.

İstisnayı nerede yakalamalı?

Nesne metodu çoğu zaman hatayı üretir, kullanıcı arayüzü veya uygulama katmanı hatayı yakalar.

# domain.py
account.withdraw(amount)  # hata üretebilir

# app.py
try:
    account.withdraw(amount)
except InsufficientBalanceError as error:
    print(error)

Account.withdraw() hatayı kendi içinde yakalayıp yalnızca print() ederse çağıran kod işlemin başarısız olduğunu güvenilir biçimde ayırt edemez.

Alıştırma — __str__ ekle

Beklenen çıktı:

2026001 — Ada
return f"{self.student_id}{self.name}"

Alıştırma — Eşitlik kuralını seç

Bir Book sınıfında şu alanlar var:

  • isbn
  • title
  • author

İki kitabın eşit sayılması için hangi alanı kullanmak daha mantıklı? Cevabınıza göre __eq__ yazın. Başka türden nesne geldiğinde NotImplemented döndürün.

Bu alıştırmada __hash__ yazmanız beklenmez. Oluşturduğunuz nesneleri set elemanı veya dict anahtarı olarak kullanmaya çalışmadan önce yukarıdaki hash notunu hatırlayın.

Alıştırma — Özel istisna

Aşağıdaki sınıfta iki farklı hata türünü ayırın: geçersiz miktar için ValueError, yetersiz stok için OutOfStockError.

Product(2).sell(5) çağrısını try/except ile yakalayın ve stok değerinin değişmediğini doğrulayın. Ardından sell(-1) çağrısının stoku artırmadığını ve ValueError ürettiğini kontrol edin.

Küçük üretim görevi — Üyelik modeli

Member sınıfı oluşturun:

  • member_id
  • name
  • active

__str__ okunabilir kısa temsil, __repr__ geliştirici temsili, __eq__ ise member_id eşitliği kullansın.

Ayrıca InactiveMemberError özel istisnasını tanımlayın. ensure_active() metodu pasif üyede bu hatayı üretsin.

Son olarak iki farklı ama aynı member_id değerine sahip nesnede == ile is sonuçlarını karşılaştırın.

Kendinizi kontrol edin

  1. __str__ ile __repr__ hangi farklı hedeflere yönelir?
  2. __eq__ neden problem alanı kararıdır?
  3. == tanımlansa bile is neden değişmez?
  4. __eq__ tanımlamak neden set/dict kullanımı açısından ayrıca düşünülmelidir?
  5. Özel istisna ne zaman ValueError’dan daha anlamlı olabilir?
  6. Neden geçersiz miktarı durum değişikliğinden önce kontrol etmek gerekir?
  7. Alan nesnesi istisnayı neden çoğu zaman kendi içinde yutmamalıdır?

Bu haftadan akılda kalması gerekenler

  • Özel metotlar sınıfımızı Python’ın veri modeliyle uyumlu hâle getirir.
  • __str__ okunabilir, __repr__ geliştirici odaklı temsildir.
  • __eq__ eşitliğin alan anlamını kodlar; hash edilebilirlik ayrı ama ilişkili bir sözleşmedir.
  • is kimlik sorusu olmaya devam eder.
  • Özel istisnalar, belirli iş kurallarını açık hata türleriyle ifade edebilir.
  • İstisna üretmeden önce geçersiz durumları doğrulamak, nesnenin invariant’ını korumaya yardımcı olur.
Back to top