È considerata una cattiva forma sollevare delle eccezioni all'interno __init__
? In tal caso, qual è il metodo accettato per generare un errore quando alcune variabili di classe vengono inizializzate come None
o di tipo errato?
È considerata una cattiva forma sollevare delle eccezioni all'interno __init__
? In tal caso, qual è il metodo accettato per generare un errore quando alcune variabili di classe vengono inizializzate come None
o di tipo errato?
Risposte:
Sollevare eccezioni all'interno __init__()
va assolutamente bene. Non esiste un altro buon modo per indicare una condizione di errore all'interno di un costruttore e ci sono molte centinaia di esempi nella libreria standard in cui la costruzione di un oggetto può sollevare un'eccezione.
La classe di errore da raccogliere, ovviamente, dipende da te. ValueError
è meglio se al costruttore è stato passato un parametro non valido.
ValueError
e TypeError
.
__init__
non è il costruttore, è l'inizializzatore. Potresti voler modificare la riga Non c'è altro buon modo per indicare una condizione di errore all'interno di un costruttore, ..
È vero che l'unico modo corretto per indicare un errore in un costruttore è sollevare un'eccezione. Questo è il motivo per cui in C ++ e in altri linguaggi orientati agli oggetti che sono stati progettati tenendo presente la sicurezza delle eccezioni, il distruttore non viene chiamato se viene generata un'eccezione nel costruttore di un oggetto (il che significa che l'inizializzazione dell'oggetto è incompleta). Questo non è spesso il caso di linguaggi di scripting, come Python. Ad esempio, il codice seguente genera un AttributeError se socket.connect () fallisce:
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()
Il motivo è che il distruttore dell'oggetto incompleto viene chiamato dopo che il tentativo di connessione ha avuto esito negativo, prima che l'inizializzazione dell'attributo stream. Non dovresti evitare di generare eccezioni dai costruttori, sto solo dicendo che è difficile scrivere codice completamente sicuro in Python. Alcuni sviluppatori di Python evitano del tutto l'uso dei distruttori, ma si tratta di un altro dibattito.
__del__
perché è scritto male. Avresti esattamente lo stesso problema se lo facessi this->p_socket->close()
in un distruttore in C ++. In C ++, non lo faresti: lasceresti che l'oggetto membro si distrugga da solo. Fai lo stesso in Python.
Non vedo alcun motivo per cui dovrebbe essere una cattiva forma.
Al contrario, una delle cose che le eccezioni sono note per fare bene, al contrario della restituzione di codici di errore, è che i codici di errore di solito non possono essere restituiti dai costruttori. Quindi, almeno in linguaggi come il C ++, sollevare eccezioni è l'unico modo per segnalare errori.
Sono d'accordo con tutto quanto sopra.
Non c'è davvero altro modo per segnalare che qualcosa è andato storto nell'inizializzazione di un oggetto se non quello di sollevare un'eccezione.
Nella maggior parte delle classi di programmi in cui lo stato di una classe dipende interamente dagli input di quella classe, potremmo aspettarci che venga generato un tipo di ValueError o TypeError.
Le classi con effetti collaterali (ad esempio uno che fa rete o grafica) potrebbero generare un errore in init se (ad esempio) il dispositivo di rete non è disponibile o non è possibile scrivere l'oggetto canvas. Mi sembra sensato perché spesso vuoi conoscere al più presto le condizioni di guasto.