Ö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), repr(obj), obj1 == obj2 veya bir koleksiyon içinde 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.
Bu hafta neleri yapabilmelisiniz?
__str__ve__repr__amaçlarını ve geri düşme davranışlarını ayırabilmeli,- Koleksiyonların eleman gösteriminde neden
__repr__kullandığını açıklayabilmeli, __eq__ile değer eşitliği tanımlayabilmeli,NotImplementedileNotImplementedErrorarasındaki farkı açıklayabilmeli,- Eşitlik tanımının hash edilebilirlik üzerindeki etkisini tanıyabilmeli,
- Özel istisna sınıfı tanımlayıp uygun temel istisna sınıfını seçebilmelisiniz.
__str__: kullanıcıya dönük temsil
print(product) ve str(product) mümkün olduğunda __str__() sonucunu kullanır.
__repr__: geliştiriciye dönük temsil
Bu derste öncelik, repr çıktısının hata ayıklamada nesnenin durumunu açık göstermesidir.
__str__ / __repr__ geri düşme davranışı
Üç pratik kural önemlidir:
- Sınıfta
__str__yok ama__repr__varsa,str(obj)/print(obj)geliştirici temsilini kullanabilir. - Sadece
__str__tanımlamakrepr(obj)davranışını değiştirmez;reprkendi varsayılan temsilinde kalır. - Liste gibi koleksiyonlar elemanlarını gösterirken
repr()kullanır. Bu yüzdenprint([product]),product.__str__()yerineproduct.__repr__()sonucunu gösterir.
print(obj) ile print([obj]) aynı protokolü kullanmaz
print(obj) kullanıcıya dönük str temsilini tercih eder. Bir listenin kendi repr çıktısı ise elemanların repr temsilini kullanır. __str__ yazdığınız hâlde print(products) çıktısının değişmemesi çoğu zaman bu yüzdendir.
__eq__: iki nesne ne zaman eşit?
== alan kuralımıza göre eşitliği; is hâlâ kimliği sorar.
Product için kod, Book için ISBN veya Student için öğrenci numarası “aynı kabul edilme” kuralı olabilir. __eq__ yazmadan önce bu kuralı problem alanında belirleyin.
NotImplemented ve NotImplementedError aynı şey değildir
İsimleri benzese de tamamen farklı rolleri vardır:
| Ad | Tür | Ne yapılır? | Tipik kullanım |
|---|---|---|---|
NotImplemented |
özel singleton değer | return edilir | __eq__ gibi ikili işlemde bu türle karşılaştırmayı desteklemiyorum |
NotImplementedError |
istisna sınıfı | raise edilir | bir davranışın burada uygulanmadığını bildirmek |
Doğru örnekler:
def __eq__(self, other):
if not isinstance(other, Product):
return NotImplementedclass Shape:
def area(self):
raise NotImplementedError("Alt sınıf hesaplamalı")return NotImplementedError ve raise NotImplemented yazmayın
- haftada
NotImplementedErrorfırlattık; bu hafta__eq__içindeNotImplementeddöndürüyoruz. Bu ayrımı özellikle koruyun.
__eq__ ve hash sözleşmesi
Eşit kabul edilen nesnelerin aynı hash değerine sahip olması gerekir. Bir sınıf __eq__ tanımlayıp uygun __hash__ tanımlamazsa örnekleri çoğu durumda hash edilemez hâle gelir. Bu derste __hash__ yazmıyoruz; mutable alan nesnelerini set elemanı veya dict anahtarı yapmadan önce eşitlik/hash tasarımını düşünmeniz yeterlidir.
Özel istisna hangi sınıftan türemeli?
Genel alan hataları için güvenli başlangıç:
class InsufficientBalanceError(Exception):
passUygulama düzeyindeki özel istisnaları doğrudan BaseException sınıfından türetmeyin; BaseException, KeyboardInterrupt ve SystemExit gibi program kontrolüyle ilgili istisnaların da köküdür.
Bazen özel hatanız aynı zamanda yerleşik bir hata kategorisinin özel biçimiyse daha anlamlı bir temel seçebilirsiniz:
class InvalidScoreError(ValueError):
passBu durumda çağıran kod ister InvalidScoreError, ister daha genel ValueError olarak yakalayabilir. Hangi tabanın doğru olduğu hata semantiğine bağlıdır; sırf özel sınıf yazmak için gereksiz hiyerarşi kurmayın.
Alan hatalarını açık ifade etmek
Nesne metodu çoğu zaman hatayı üretir, uygulama/UI katmanı hatayı yakalar. Alan nesnesi hatayı kendi içinde print() edip yutarsa çağıran kod başarısızlığı güvenilir biçimde ayırt edemez.
Alıştırma — __str__ ekle
return f"{self.student_id} — {self.name}"Alıştırma — repr farkını gözlemle
Bir sınıfa hem __str__ hem __repr__ ekleyin. print(obj), repr(obj) ve print([obj]) sonuçlarını yan yana yazdırın; hangi çağrının hangi özel metoda gittiğini açıklayın.
Alıştırma — Eşitlik kuralını seç
Book(isbn, title, author) sınıfında eşitliği ISBN üzerinden tanımlayın. Başka türden nesne geldiğinde NotImplemented döndürün. Bu alıştırmada __hash__ yazmanız beklenmez.
Küçük üretim görevi — Üyelik modeli
Member(member_id, name, active) sınıfı oluşturun. __str__, __repr__, __eq__ tanımlayın; eşitlik member_id üzerinden olsun. InactiveMemberError(Exception) özel istisnasını ve ensure_active() davranışını ekleyin.
Çalışır kod teslimi: İki farklı ama aynı member_id değerine sahip nesne için == ve is sonuçlarını doğrulayın; print(member) ve print([member]) farkını gösterin; pasif üyede özel istisnanın üretildiğini test edin. Ayrıca NotImplemented ile NotImplementedError için birer doğru kullanım satırı ekleyin.
Kendinizi kontrol edin
__str__ile__repr__hangi hedeflere yönelir?- Liste elemanlarını gösterirken neden
__repr__önemlidir? - Sadece
__repr__varsaprint(obj)ne yapabilir? NotImplementedileNotImplementedErrorarasındaki fark nedir?__eq__neden problem alanı kararıdır?- Özel istisnalar neden genellikle
Exceptionveya anlamlı bir alt sınıftan türetilir? ValueErroralt sınıfı yapmak hangi durumda anlamlı olabilir?
Bu haftadan akılda kalması gerekenler
- Özel metotlar sınıfımızı Python’ın veri modeliyle uyumlu hâle getirir.
__str__kullanıcı,__repr__geliştirici odaklı temsildir; koleksiyonlar elemanlardareprkullanır.NotImplementeddöndürülen özel bir değerdir;NotImplementedErrorfırlatılan bir istisnadır.__eq__eşitliğin alan anlamını kodlar; hash edilebilirlik ayrı ama ilişkili bir sözleşmedir.- Özel istisnalar çoğunlukla
Exceptionveya semantik olarak daha uygun yerleşik bir istisna sınıfından türetilir.