Python: __init__ içinde istisnaları yükseltmek kötü bir biçim mi?


128

İçeride istisnalar ortaya çıkarmak kötü bir form olarak kabul edilir __init__mi? Öyleyse, belirli sınıf değişkenleri olarak Noneveya yanlış türde başlatıldığında hata atmanın kabul edilen yöntemi nedir?


C'de, yıkıcıda bir istisna oluşturmak kötü bir biçimdir, ancak kurucu iyi olmalıdır.
Calyth

6
@Calyth, C ++ 'ı kastediyorsunuz - C'de kurucu veya yıkıcı yok
Alex Martelli

4
... veya istisnalar, bu konuda.
Matt Wilding

@Calyth: lol, lütfen masum bir yazım hatası tarafından yapılan anlamsız ifadeyi kaldırın ;-)
lpapp

4
@lpapp evet. C ++. FML. Ve bu yorumu düzenleyemedim. Böylece internet benim aptallığımı belgeleyecek;)
Calyth

Yanıtlar:


159

İçeride istisnalar yaratmak __init__()kesinlikle iyidir. Bir kurucu içinde bir hata durumunu belirtmenin başka iyi bir yolu yoktur ve standart kitaplıkta bir nesne oluşturmanın bir istisna oluşturabileceği yüzlerce örnek vardır.

Elbette yükseltilecek hata sınıfı size bağlıdır. ValueErrorkurucuya geçersiz bir parametre geçirilmişse en iyisidir.


14
Yapıcıda en çok kullanılan istisnalar ValueErrorve TypeError.
Denis Otkidach

9
Sadece __init__bunun kurucu olmadığını, onun başlatıcı olduğunu belirtmek isterim. Satırı düzenlemek isteyebilirsiniz Bir kurucuda bir hata durumunu belirtmenin başka iyi bir yolu yok, ..
Haris

26

Yapıcıdaki bir hatayı göstermenin tek uygun yolunun bir istisna oluşturmak olduğu doğrudur. Bu nedenle, C ++ 'da ve istisnai güvenlik göz önünde bulundurularak tasarlanmış diğer nesne yönelimli dillerde, bir nesnenin yapıcısında bir istisna atılırsa yıkıcı çağrılmaz (yani nesnenin başlatılması eksiktir). Python gibi komut dosyası dillerinde bu genellikle geçerli değildir. Örneğin, socket.connect () başarısız olursa aşağıdaki kod bir AttributeError atar:

class NetworkInterface:
    def __init__(self, address)
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect(address)
        self.stream = self.socket.makefile()

    def __del__(self)
        self.stream.close()
        self.socket.close()

Bunun nedeni, tamamlanmamış nesnenin yıkıcısının, bağlantı girişimi başarısız olduktan sonra, akış özniteliği başlatılmadan önce çağrılmasıdır. Yapıcılardan istisnalar atmaktan kaçınmamalısınız, sadece Python'da tamamen istisna güvenli kod yazmanın zor olduğunu söylüyorum. Bazı Python geliştiricileri yıkıcıları kullanmaktan tamamen kaçınırlar, ancak bu başka bir tartışma konusudur.


Bu cevap gerçekten kullanışlıdır. Sadece "yeşil ışıktan" bahsetmiyor, "yıkıcı" ile bir örnekten bahsediyor.
lpapp

Python kodunuz __del__kötü yazılmış olduğu için başarısız oluyor . this->p_socket->close()C ++ 'da bir yıkıcıda yapsaydınız, tam olarak aynı sorunu yaşarsınız. C ++ 'da bunu yapmazsınız - üye nesnesinin kendini yok etmesine izin verirsiniz. Python'da da aynısını yapın.
Eric

1
@Eric C ++ 'da sorun yaşamazdım çünkü C ++ düzgün şekilde başlatılmamış nesneleri yok etmez . Aslında, C ++ 'da kaynakları yapıcıda tahsis etmek ve yıkıcıda ayırmak çok yaygın bir deyimdir . Üye nesnenin kendisini yok etmesini (yıkıcıdaki kaynakları serbest bırakarak) önerirsiniz - o zaman üye sınıfı yazarken aynı sorun ortaya çıkar.
Seppo Enarvi

11

Kötü biçimde olması için herhangi bir sebep görmüyorum.

Hata kodları dönen aksine tersine, istisnalar iyi yapıyor tanınırlar şeylerden birisi üzerine, hata kodları genellikle olmasıdır olamaz yapıcıları tarafından iade edilmesi. Bu nedenle, en azından C ++ gibi dillerde, istisnaları artırmak, hataları bildirmenin tek yoludur.


6

Standart kütüphane diyor ki:

>>> f = file("notexisting.txt")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'notexisting.txt'

Ayrıca neden kötü bir form olarak görülmesi için herhangi bir neden görmüyorum.


3

ValueErrorYerleşik istisna için mükemmel bir durum olduğunu düşünüyorum .


2

Yukarıdakilerin hepsine katılıyorum.

Bir nesnenin ilklendirilmesinde bir şeylerin ters gittiğini belirtmenin bir istisna yaratmaktan başka bir yolu yoktur.

Bir sınıfın durumunun tamamen o sınıfın girdilerine bağlı olduğu çoğu program sınıfında, bir tür ValueError veya TypeError'ın ortaya çıkmasını bekleyebiliriz.

Yan etkileri olan sınıflar (örneğin, ağ veya grafik yapan), (örneğin) ağ aygıtı kullanılamıyorsa veya tuval nesnesine yazılamıyorsa, init'te bir hata oluşturabilir. Bu bana mantıklı geliyor çünkü çoğu zaman başarısızlık koşullarını mümkün olan en kısa sürede bilmek istersiniz.


2

Bazı durumlarda init'ten hataları yükseltmek kaçınılmazdır, ancak init'te çok fazla çalışma yapmak kötü bir tarzdır. Bir fabrika veya sahte fabrika yapmayı düşünmelisiniz - ayarlanmış nesneyi döndüren basit bir sınıf yöntemi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.