Cattura più eccezioni in una riga (tranne blocco)


2759

So che posso fare:

try:
    # do something that may fail
except:
    # do this if ANYTHING goes wrong

Posso anche fare questo:

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreTooShortException:
    # stand on a ladder

Ma se voglio fare la stessa cosa in due diverse eccezioni, la cosa migliore che mi viene in mente in questo momento è di fare questo:

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreBeingMeanException:
    # say please

Esiste un modo in cui posso fare qualcosa del genere (poiché l'azione da intraprendere in entrambe le eccezioni è:) say please:

try:
    # do something that may fail
except IDontLikeYouException, YouAreBeingMeanException:
    # say please

Ora questo non funzionerà davvero, poiché corrisponde alla sintassi per:

try:
    # do something that may fail
except Exception, e:
    # say please

Quindi, il mio sforzo per cogliere le due distinte eccezioni non si manifesta esattamente.

C'è un modo per fare questo?


6
Si noti che in Python 3, quest'ultima non è più una sintassi valida.
Gerrit,

Risposte:


3726

Dalla documentazione di Python :

Una clausola salvo può nominare più eccezioni come una tupla tra parentesi, ad esempio

except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

Oppure, solo per Python 2:

except (IDontLikeYouException, YouAreBeingMeanException), e:
    pass

Separare l'eccezione dalla variabile con una virgola funzionerà comunque in Python 2.6 e 2.7, ma ora è deprecato e non funziona in Python 3; ora dovresti usare as.


9
L'ho provato ... con a list, e ha provocato a TypeError. Sembra che gli errori debbano essere presenti in modo tupleda poter funzionare come previsto.
BallpointBen,

4
Perché avresti mai usato un elenco quando vedi chiaramente che è documentato che in questo caso è necessaria una tupla?
Mechanical_meat

6
Non era chiaro se la "tupla tra parentesi" fosse semplicemente sintattica o se fosse necessaria una tupla in buona fede. "Parentesi" è fuorviante perché è possibile creare una tupla senza parentesi altrove e quindi utilizzarla nella exceptriga. È necessariamente tra parentesi solo se creato nella exceptriga.
BallpointBen,

5
@JosephBani, che dire delle espressioni del generatore?
jammertheprogrammer

12
@JosephBani Non è affatto vero. In 2 + (x * 2), non (x * 2)è certamente una tupla. Le parentesi sono un costrutto generale di raggruppamento. La caratteristica che definisce una tupla è che contiene una virgola . Vedi la documentazione di Python : "Nota che in realtà è la virgola che crea una tupla, non le parentesi."
Soren Bjornstad,

314

Come posso rilevare più eccezioni in una riga (tranne il blocco)

Fai questo:

try:
    may_raise_specific_errors():
except (SpecificErrorOne, SpecificErrorTwo) as error:
    handle(error) # might log or have some other default behavior...

Le parentesi sono necessarie a causa della sintassi precedente che utilizzava le virgole per assegnare l'oggetto errore a un nome. La asparola chiave viene utilizzata per l'assegnazione. Puoi usare qualsiasi nome per l'oggetto errore, preferisco errorpersonalmente.

La migliore pratica

Per fare ciò attualmente e in modo compatibile con Python, devi separare le Eccezioni con virgole e racchiuderle tra parentesi per differenziarle dalla sintassi precedente che ha assegnato l'istanza dell'eccezione a un nome di variabile seguendo il tipo Eccezione da intercettare con un virgola.

Ecco un esempio di utilizzo semplice:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError): # the parens are necessary
    sys.exit(0)

Sto specificando solo queste eccezioni per evitare di nascondere bug, che se incontro mi aspetto la traccia dello stack completo.

Questo è documentato qui: https://docs.python.org/tutorial/errors.html

Puoi assegnare l'eccezione a una variabile, ( eè comune, ma potresti preferire una variabile più dettagliata se hai una lunga gestione delle eccezioni o il tuo IDE evidenzia solo selezioni più grandi di quelle, come la mia.) L'istanza ha un attributo args. Ecco un esempio:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError) as err: 
    print(err)
    print(err.args)
    sys.exit(0)

Si noti che in Python 3, l' erroggetto non rientra nell'ambito quando il exceptblocco viene concluso.

Obsoleto

È possibile che venga visualizzato un codice che assegna l'errore con una virgola. Questo utilizzo, l'unico modulo disponibile in Python 2.5 e precedenti, è obsoleto e se si desidera che il codice sia compatibile in avanti in Python 3, è necessario aggiornare la sintassi per utilizzare il nuovo modulo:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError), err: # don't do this in Python 2.6+
    print err
    print err.args
    sys.exit(0)

Se vedi l'assegnazione del nome virgola nella tua base di codice e stai usando Python 2.5 o versione successiva, passa al nuovo modo di farlo in modo che il tuo codice rimanga compatibile durante l'aggiornamento.

Il suppressgestore del contesto

La risposta accettata è in realtà 4 righe di codice, minimo:

try:
    do_something()
except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

La try, except, passlinee può essere gestita in una singola linea con il contesto sopprimere gestore, disponibile in Python 3.4 :

from contextlib import suppress

with suppress(IDontLikeYouException, YouAreBeingMeanException):
     do_something()

Quindi, quando vuoi fare passalcune eccezioni, usa suppress.


2
Buona aggiunta suppress, molto più leggibile che non solo passsuexcept
Mache

50

Dalla documentazione di Python -> 8.3 Gestione delle eccezioni :

Una trydichiarazione può avere più di una clausola except, per specificare gestori di differenti eccezioni. Verrà eseguito al massimo un gestore. I gestori gestiscono solo le eccezioni che si verificano nella corrispondente clausola try, non in altri gestori della stessa istruzione try. Una clausola exception può nominare più eccezioni come una tupla tra parentesi, ad esempio:

except (RuntimeError, TypeError, NameError):
    pass

Nota che sono necessarie le parentesi attorno a questa tupla, perché tranne ValueError, e:era la sintassi usata per ciò che è normalmente scritto come except ValueError as e:nel moderno Python (descritto di seguito). La vecchia sintassi è ancora supportata per la compatibilità con le versioni precedenti. Questo significa che except RuntimeError, TypeErrornon è equivalente a except (RuntimeError, TypeError):ma a except RuntimeError as TypeError:cui non è quello che vuoi.


35

Se usi spesso un numero elevato di eccezioni, puoi pre-definire una tupla, quindi non è necessario reinserirle più volte.

#This example code is a technique I use in a library that connects with websites to gather data

ConnectErrs  = (URLError, SSLError, SocketTimeoutError, BadStatusLine, ConnectionResetError)

def connect(url, data):
    #do connection and return some data
    return(received_data)

def some_function(var_a, var_b, ...):
    try: o = connect(url, data)
    except ConnectErrs as e:
        #do the recovery stuff
    blah #do normal stuff you would do if no exception occurred

APPUNTI:

  1. Se anche tu hai bisogno di cogliere altre eccezioni rispetto a quelle nella tupla predefinita, dovrai definire un altro tranne blocco.

  2. Se non riesci a tollerare una variabile globale, definiscila in main () e passala dove necessario ...


17

Uno dei modi per farlo è ...

try:
   You do your operations here;
   ......................
except(Exception1[, Exception2[,...ExceptionN]]]):
   If there is any exception from the given exception list, 
   then execute this block.
   ......................
else:
   If there is no exception then execute this block. 

e un altro modo è quello di creare un metodo che esegue un'attività eseguita da exceptblocco e chiamarlo attraverso tutto il exceptblocco che si scrive ..

try:
   You do your operations here;
   ......................
except Exception1:
    functionname(parameterList)
except Exception2:
    functionname(parameterList)
except Exception3:
    functionname(parameterList)
else:
   If there is no exception then execute this block. 

def functionname( parameters ):
   //your task..
   return [expression]

So che il secondo non è il modo migliore per farlo, ma sto solo mostrando il numero di modi per farlo.


Sto usando il secondo perché ho due diverse eccezioni che devono essere elaborate in modo diverso. C'è qualcosa di sbagliato nel farlo in quel modo?
Majikman,

@majikman Il secondo metodo con più clausole, ciascuna delle quali chiama la stessa funzione, non è la migliore quando stai cercando di non ripetere te stessa e fare la stessa cosa per due eccezioni. (Vedi le altre risposte per il modo giusto di farlo). Tuttavia, avere più exceptclausole è normale quando si desidera gestire le eccezioni in modo diverso.
Eponimo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.