Risposte:
Come faccio a lanciare / sollevare manualmente un'eccezione in Python?
Utilizzare il costruttore Eccezione più specifico che si adatta semanticamente al problema .
Sii specifico nel tuo messaggio, ad esempio:
raise ValueError('A very specific bad thing happened.')
Evita di sollevare un generico Exception
. Per catturarlo, dovrai catturare tutte le altre eccezioni più specifiche che lo sottoclassano.
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
Per esempio:
def demo_bad_catch():
try:
raise ValueError('Represents a hidden bug, do not catch this')
raise Exception('This is the exception you expect to handle')
except Exception as error:
print('Caught this error: ' + repr(error))
>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)
E le catture più specifiche non colpiranno l'eccezione generale:
def demo_no_catch():
try:
raise Exception('general exceptions not caught by specific handling')
except ValueError as e:
print('we will not catch exception: Exception')
>>> demo_no_catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling
raise
dichiarazioneUtilizzare invece il costruttore Eccezione più specifico che si adatta semanticamente al problema .
raise ValueError('A very specific bad thing happened')
che consente anche di trasmettere un numero arbitrario di argomenti al costruttore:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
Questi argomenti sono accessibili dal args
attributo sul Exception
oggetto. Per esempio:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
stampe
('message', 'foo', 'bar', 'baz')
In Python 2.5 è message
stato aggiunto un attributo effettivo BaseException
a favore di incoraggiare gli utenti a sottoclassare Eccezioni e smettere di usare args
, ma l'introduzione message
e la deprecazione originale di args sono state ritirate .
except
clausolaQuando si è all'interno di una clausola exception, è possibile, ad esempio, registrare che si sia verificato un tipo specifico di errore e quindi ripetere il rilancio. Il modo migliore per farlo preservando la traccia dello stack è usare un'istruzione di rilancio nudo. Per esempio:
logger = logging.getLogger(__name__)
try:
do_something_in_app_that_breaks_easily()
except AppError as error:
logger.error(error)
raise # just this!
# raise AppError # Don't do this, you'll lose the stack trace!
Puoi conservare lo stacktrace (e il valore dell'errore) con sys.exc_info()
, ma questo è molto più soggetto a errori e ha problemi di compatibilità tra Python 2 e 3 , preferisci usare un bare raise
per rilanciare.
Per spiegare: sys.exc_info()
restituisce il tipo, il valore e il traceback.
type, value, traceback = sys.exc_info()
Questa è la sintassi in Python 2 - nota che non è compatibile con Python 3:
raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
Se lo desideri, puoi modificare ciò che accade con il tuo nuovo rilancio, ad esempio impostando nuovo args
per l'istanza:
def error():
raise ValueError('oops!')
def catch_error_modify_message():
try:
error()
except ValueError:
error_type, error_instance, traceback = sys.exc_info()
error_instance.args = (error_instance.args[0] + ' <modification>',)
raise error_type, error_instance, traceback
E abbiamo preservato l'intero traceback durante la modifica degli arg. Nota che questa non è una buona pratica ed è una sintassi non valida in Python 3 (rendendo molto più difficile mantenere la compatibilità).
>>> catch_error_modify_message()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch_error_modify_message
File "<stdin>", line 2, in error
ValueError: oops! <modification>
In Python 3 :
raise error.with_traceback(sys.exc_info()[2])
Ancora: evita di manipolare manualmente i traceback. È meno efficiente e più soggetto a errori. E se stai usando il threading e sys.exc_info
potresti persino avere il traceback sbagliato (specialmente se stai usando la gestione delle eccezioni per il flusso di controllo - che personalmente tenderei ad evitare).
In Python 3, è possibile concatenare le eccezioni, che conservano i traceback:
raise RuntimeError('specific message') from error
Attenzione:
Questi possono facilmente nascondere e persino entrare nel codice di produzione. Vuoi sollevare un'eccezione, e farli genererà un'eccezione, ma non quella prevista!
Valido in Python 2, ma non in Python 3 è il seguente:
raise ValueError, 'message' # Don't do this, it's deprecated!
Valido solo nelle versioni molto più vecchie di Python (2.4 e precedenti), potresti ancora vedere persone che sollevano stringhe:
raise 'message' # really really wrong. don't do this.
In tutte le versioni moderne, questo aumenterà effettivamente a TypeError
, perché non stai aumentando un BaseException
tipo. Se non stai verificando la giusta eccezione e non hai un revisore a conoscenza del problema, potrebbe entrare in produzione.
Sollevo eccezioni per avvertire i consumatori della mia API se la usano in modo errato:
def api_func(foo):
'''foo should be either 'baz' or 'bar'. returns something very useful.'''
if foo not in _ALLOWED_ARGS:
raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))
"Voglio fare un errore di proposito, in modo che andrebbe in tranne"
È possibile creare i propri tipi di errore, se si desidera indicare che qualcosa di specifico non va nella propria applicazione, è sufficiente sottoclassare il punto appropriato nella gerarchia delle eccezioni:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
e utilizzo:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
raise sys.exc_info()[0], (sys.exc_info()[1], my_extra_info), sys.exc_info()[2]
sembra fare quello che voglio e non ho mai avuto problemi con esso. Ma sembra confuso, e non una pratica accettata. Esiste un modo migliore?
Exception
tua classe genitore - puoi sottoclassare qualcosa di più specifico e dovresti farlo se ha senso.
AppError
un'eccezione non definita . Potrebbe essere meglio usare un errore incorporato comeAttributeError
NON FARE QUESTO . Crescere un nuda
Exception
è assolutamente non la cosa giusta da fare; vedi invece l'eccellente risposta di Aaron Hall .
Non posso ottenere molto più pitonico di così:
raise Exception("I know python!")
Vedi i documenti dell'istruzione raise per Python se desideri maggiori informazioni.
In Python3 ci sono 4 diverse sintassi per le eccezioni rasing:
1. raise exception
2. raise exception (args)
3. raise
4. raise exception (args) from original_exception
1. aumentare l'eccezione rispetto a 2. aumentare l'eccezione (args)
Se si utilizza raise exception (args)
per sollevare un'eccezione, args
verrà stampato quando si stampa l'oggetto dell'eccezione, come mostrato nell'esempio seguente.
#raise exception (args)
try:
raise ValueError("I have raised an Exception")
except ValueError as exp:
print ("Error", exp) # Output -> Error I have raised an Exception
#raise execption
try:
raise ValueError
except ValueError as exp:
print ("Error", exp) # Output -> Error
3.raise
raise
L'istruzione senza argomenti ripristina l'ultima eccezione. Ciò è utile se è necessario eseguire alcune azioni dopo aver rilevato l'eccezione e quindi si desidera aumentare nuovamente. Ma se prima non c'erano eccezioni, l' raise
affermazione genera l' TypeError
eccezione.
def somefunction():
print("some cleaning")
a=10
b=0
result=None
try:
result=a/b
print(result)
except Exception: #Output ->
somefunction() #some cleaning
raise #Traceback (most recent call last):
#File "python", line 8, in <module>
#ZeroDivisionError: division by zero
4. solleva l'eccezione (args) da original_exception
Questa istruzione viene utilizzata per creare un concatenamento di eccezioni in cui un'eccezione sollevata in risposta a un'altra eccezione può contenere i dettagli dell'eccezione originale, come mostrato nell'esempio seguente.
class MyCustomException(Exception):
pass
a=10
b=0
reuslt=None
try:
try:
result=a/b
except ZeroDivisionError as exp:
print("ZeroDivisionError -- ",exp)
raise MyCustomException("Zero Division ") from exp
except MyCustomException as exp:
print("MyException",exp)
print(exp.__cause__)
Produzione:
ZeroDivisionError -- division by zero
MyException Zero Division
division by zero
exception(args)
overexception (args)
raise exception(args) from None
da dire che l'eccezione attualmente attiva è stata gestita e non è più interessante. Altrimenti se si genera un'eccezione all'interno di un except
blocco e non viene gestita, i traceback per entrambe le eccezioni verranno visualizzati separati dal messaggio "Durante la gestione dell'eccezione sopra, si è verificata un'altra eccezione"
Per il caso comune in cui è necessario lanciare un'eccezione in risposta ad alcune condizioni impreviste e che non si intende mai catturare, ma semplicemente fallire rapidamente per consentire di eseguire il debug da lì, se mai dovesse accadere, il più logico sembra essere AssertionError
:
if 0 < distance <= RADIUS:
#Do something.
elif RADIUS < distance:
#Do something.
else:
raise AssertionError("Unexpected value of 'distance'!", distance)
ValueError
quello AssertionError
perché non ci sono problemi con un'asserzione (perché qui non ne viene fatta nessuna) - il problema è con un valore. Se vuoi davvero un AssertionError
in questo caso, scrivi assert distance > 0, 'Distance must be positive'
. Ma non dovresti controllare l'errore in questo modo perché le asserzioni possono essere disattivate ( python -O
).
-O
.
Leggi prima le risposte esistenti, questo è solo un addendum.
Si noti che è possibile sollevare eccezioni con o senza argomenti.
Esempio:
raise SystemExit
esce dal programma ma potresti voler sapere cosa è successo, quindi puoi usarlo.
raise SystemExit("program exited")
questo stamperà "programma uscito" su stderr prima di chiudere il programma.
raise SystemExit()
sarebbe la scelta migliore? Perché il primo funziona anche?
Un altro modo per generare un'eccezione è assert
. È possibile utilizzare assert per verificare che una condizione sia soddisfatta, altrimenti si solleverà AssertionError
. Per maggiori dettagli dai un'occhiata qui .
def avg(marks):
assert len(marks) != 0,"List is empty."
return sum(marks)/len(marks)
mark2 = [55,88,78,90,79]
print("Average of mark2:",avg(mark2))
mark1 = []
print("Average of mark1:",avg(mark1))
Solo per notare: ci sono momenti in cui vuoi gestire eccezioni generiche. Se stai elaborando un mucchio di file e stai registrando i tuoi errori, potresti voler rilevare qualsiasi errore che si verifica per un file, registrarlo e continuare a elaborare il resto dei file. In tal caso, a
try:
foo()
except Exception as e:
print(str(e)) # Print out handled error
bloccare un buon modo per farlo. Avrai comunque bisogno di raise
eccezioni specifiche in modo da sapere cosa significano, però.
Per questo dovresti imparare la dichiarazione di rilancio di Python. Dovrebbe essere tenuto all'interno del blocco try. Esempio -
try:
raise TypeError #remove TypeError by any other error if you want
except TypeError:
print('TypeError raised')
raise
è ciò di cui avevo bisogno per poter eseguire il debug degli errori personalizzato a più livelli di esecuzione del codice senza interrompere la traccia dello stack.