7.1 Creazione di eccezioni personalizzate
A volte le eccezioni standard di Python non soddisfano completamente
le esigenze della tua applicazione. In questi casi, puoi creare
le tue eccezioni personalizzate, ereditandole dalla classe di base
Exception
o da qualsiasi altra classe di eccezioni appropriata.
Fondamenti della creazione di eccezioni personalizzate
Creare un'eccezione personalizzata significa definire
una nuova classe ereditata dalla classe di base
Exception
. Puoi aggiungere i tuoi metodi e
attributi per fornire informazioni aggiuntive sull'errore.
Esempio di creazione di una semplice eccezione personalizzata
Passo 1: Definizione di un'eccezione personalizzata
class MyCustomError(Exception):
"""Classe per un'eccezione personalizzata."""
pass
Passo 2: Utilizzo dell'eccezione personalizzata
def check_value(value):
if value < 0:
raise MyCustomError("Il valore non deve essere inferiore a zero")
try:
check_value(-1)
except MyCustomError as e:
print(f"Si è verificata un'eccezione personalizzata: {e}")
È tutto molto semplice. È importante che la tua eccezione erediti dalla classe Exception
o da uno dei suoi
discendenti.
7.2 Creazione di un'eccezione con attributi aggiuntivi
Puoi aggiungere attributi e metodi alla tua classe di eccezione per trasmettere informazioni aggiuntive sull'errore verificatosi.
Esempio:
class NegativeValueError( Exception ):
"""Classe per un'eccezione personalizzata quando il valore è negativo."""
def __init__(self, value, message = "Il valore non deve essere inferiore a zero"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
Utilizzo dell'eccezione con attributi aggiuntivi
def check_value(value):
if value < 0:
raise NegativeValueError(value)
try:
check_value(-1)
except NegativeValueError as e:
print(f"Si è verificata un'eccezione personalizzata: {e}")
La nostra eccezione è una classe ereditata dalla classe Exception
. Pertanto, puoi fare con essa tutto ciò che puoi fare
con qualsiasi altra classe: aggiungere campi, metodi, parametri del costruttore, ecc.
Tutto per la tua comodità e quella dei programmatori che intercetteranno le tue eccezioni.
7.3 Creazione di gerarchie di eccezioni personalizzate
Per applicazioni più complesse, è utile creare gerarchie di eccezioni personalizzate. Questo permette di raggruppare eccezioni correlate e semplifica la loro gestione.
Esempio:
class ApplicationError(Exception):
"""Classe base per tutte le eccezioni dell'applicazione."""
pass
class NegativeValueError(ApplicationError):
"""Classe per un'eccezione personalizzata quando il valore è negativo."""
def __init__(self, value, message="Il valore non deve essere inferiore a zero"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
class ValueTooLargeError(ApplicationError):
"""Classe per un'eccezione personalizzata quando il valore è troppo grande."""
def __init__(self, value, message="Valore troppo grande"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
Utilizzo della gerarchia di eccezioni personalizzate
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except NegativeValueError as e:
print(f"Si è verificata un'eccezione: {e}")
except ValueTooLargeError as e:
print(f"Si è verificata un'eccezione: {e}")
except ApplicationError as e:
print(f"Eccezione generale dell'applicazione: {e}")
7.4 Ordine di cattura delle eccezioni
Quando si catturano eccezioni, specialmente da una stessa gerarchia, è importante indicarne l'ordine corretto. Anche se il codice
all'interno dei blocchi except
non viene mai eseguito simultaneamente, la classe base dell'eccezione può
catturare eccezioni di tutte le classi figlie.
Ad esempio, il codice:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except ApplicationError as e: # catturerà eccezioni del tipo ApplicationError e tutte le sue sottoclassi
print(f"Eccezione generale dell'applicazione: {e}")
Nel blocco except
, verranno catturate eccezioni del tipo ApplicationError
e di tutte le sue classi figlie.
E poiché tutte le eccezioni sono discendenti della classe Exception
, tale codice catturerà tutte le eccezioni:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except Exception as e:
print(f"Cattura di tutte le eccezioni: {e}")
except ApplicationError as e: # Questo codice non verrà mai eseguito
print(f"Eccezione generale dell'applicazione: {e}")
La cattura delle eccezioni nel blocco except ApplicationError
non avverrà mai, poiché il blocco except Exception
catturerà
tutte le eccezioni di tipo Exception
e qualsiasi suo discendente.
Soluzione
Pertanto, è consuetudine catturare le eccezioni in ordine inverso rispetto all'ereditarietà: più il classe è vicina alla classe Exception
, più è bassa.
Esempio:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except NegativeValueError as e:
print(f"Si è verificata un'eccezione: {e}")
except ApplicationError as e:
print(f"Eccezione generale dell'applicazione: {e}")
except Exception as e:
print(f"Cattura di tutte le eccezioni: {e}")
In questo esempio, i blocchi except
sono disposti in un ordine che corrisponde alla loro gerarchia di ereditarietà:
prima vengono intercettate le eccezioni più specifiche, come NegativeValueError
, poi quelle più generali, come ApplicationError
.
Questo permette di gestire correttamente le eccezioni ed evitare situazioni in cui un gestore più generale cattura un'eccezione prima che i blocchi except
più specializzati possano gestirla.
GO TO FULL VERSION