Détectez plusieurs exceptions sur une seule ligne (sauf le bloc)

2759

Je sais que je peux faire:

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

Je peux aussi faire ça:

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

Mais si je veux faire la même chose à l'intérieur de deux exceptions différentes, le mieux que je puisse penser en ce moment est de le faire:

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

Existe-t-il un moyen de faire quelque chose comme ça (puisque l'action à entreprendre dans les deux exceptions est de say please):

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

Maintenant, cela ne fonctionnera vraiment pas, car il correspond à la syntaxe de:

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

Donc, mon effort pour attraper les deux exceptions distinctes ne passe pas exactement.

Y a-t-il un moyen de faire cela?

inspecteurG4dget
la source
6
Notez qu'en Python 3, cette dernière n'est plus une syntaxe valide.
gerrit

Réponses:

3727

Depuis la documentation Python :

Une clause except peut nommer plusieurs exceptions comme un tuple entre parenthèses, par exemple

except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

Ou, pour Python 2 uniquement:

except (IDontLikeYouException, YouAreBeingMeanException), e:
    pass

Séparer l'exception de la variable par une virgule fonctionnera toujours dans Python 2.6 et 2.7, mais est désormais obsolète et ne fonctionne pas dans Python 3; maintenant vous devriez utiliser as.

viande_mecanique
la source
9
Je l'ai essayé ... avec un list, et ça a donné un TypeError. On dirait que les erreurs doivent être dans un tuplepour que la capture fonctionne comme prévu.
BallpointBen
4
Pourquoi auriez-vous jamais utilisé une liste lorsque vous voyez clairement qu'il est documenté qu'un tuple est nécessaire dans ce cas?
mechanical_meat
6
Il n'était pas clair si le "tuple entre parenthèses" était simplement syntaxique ou si un tuple authentique était requis. "Parenthèse" est trompeur car vous pouvez créer un tuple sans parenthèses ailleurs, puis l'utiliser dans la exceptligne. Il n'est nécessairement entre parenthèses que s'il est créé dans la exceptligne.
BallpointBen
5
@JosephBani, qu'en est-il des expressions de générateur?
jammertheprogrammer
12
@JosephBani Ce n'est pas vrai du tout. En 2 + (x * 2), (x * 2)n'est certainement pas un tuple. Les parenthèses sont une construction de regroupement générale. La caractéristique qui définit un tuple est qu'il contient une virgule - voir la documentation Python : "Notez que c'est en fait la virgule qui fait un tuple, pas les parenthèses."
Soren Bjornstad
314

Comment intercepter plusieurs exceptions sur une seule ligne (sauf le bloc)

Faites ceci:

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

Les parenthèses sont requises en raison d'une syntaxe plus ancienne qui utilisait les virgules pour attribuer l'objet d'erreur à un nom. Le asmot-clé est utilisé pour l'affectation. Vous pouvez utiliser n'importe quel nom pour l'objet d'erreur, je préfère errorpersonnellement.

Meilleur entrainement

Pour ce faire d'une manière actuellement et à l'avenir compatible avec Python, vous devez séparer les exceptions avec des virgules et les encapsuler avec des parenthèses pour différencier de la syntaxe précédente qui affectait l'instance d'exception à un nom de variable en suivant le type d'exception à intercepter avec un virgule.

Voici un exemple d'utilisation simple:

import sys

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

Je ne spécifie que ces exceptions pour éviter de masquer les bogues, ce qui, si je le rencontre, m'attend à la trace complète de la pile.

Ceci est documenté ici: https://docs.python.org/tutorial/errors.html

Vous pouvez attribuer l'exception à une variable ( ec'est courant, mais vous préférerez peut-être une variable plus détaillée si vous avez une longue gestion des exceptions ou si votre IDE ne met en surbrillance que des sélections plus grandes que la mienne.) L'instance a un attribut args. Voici un exemple:

import sys

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

Notez qu'en Python 3, l' errobjet tombe hors de portée lorsque le exceptbloc est terminé.

Obsolète

Vous pouvez voir du code qui attribue l'erreur avec une virgule. Cette utilisation, le seul formulaire disponible dans Python 2.5 et versions antérieures, est déconseillée, et si vous souhaitez que votre code soit compatible avec Python 3, vous devez mettre à jour la syntaxe pour utiliser le nouveau formulaire:

import sys

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

Si vous voyez l'attribution du nom de virgule dans votre base de code et que vous utilisez Python 2.5 ou supérieur, passez à la nouvelle façon de le faire afin que votre code reste compatible lors de la mise à niveau.

Le suppressgestionnaire de contexte

La réponse acceptée est en réalité 4 lignes de code, au minimum:

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

Le try, except, les passlignes peuvent être traitées en une seule ligne avec le gestionnaire de contexte de suppression, disponible en Python 3.4 :

from contextlib import suppress

with suppress(IDontLikeYouException, YouAreBeingMeanException):
     do_something()

Donc, quand vous voulez passsur certaines exceptions, utilisez suppress.

Aaron Hall
la source
2
Bon ajout de suppress, beaucoup plus facile à lire que de simplement faire passsurexcept
Mache
50

De la documentation Python -> 8.3 Gestion des exceptions :

Une tryinstruction peut avoir plusieurs clauses except, pour spécifier des gestionnaires pour différentes exceptions. Au plus, un gestionnaire sera exécuté. Les gestionnaires ne gèrent que les exceptions qui se produisent dans la clause try correspondante, pas dans les autres gestionnaires de la même instruction try. Une clause except peut nommer plusieurs exceptions comme un tuple entre parenthèses, par exemple:

except (RuntimeError, TypeError, NameError):
    pass

Notez que les parenthèses autour de ce tuple sont obligatoires, car excepté ValueError, e:la syntaxe utilisée pour ce qui est normalement écrit comme except ValueError as e:dans Python moderne (décrit ci-dessous). L'ancienne syntaxe est toujours prise en charge pour une compatibilité descendante. Cela ne signifie except RuntimeError, TypeErrorpas except (RuntimeError, TypeError):mais except RuntimeError as TypeError:ce n'est pas ce que vous voulez.

fedorqui 'SO arrête de nuire'
la source
35

Si vous utilisez fréquemment un grand nombre d'exceptions, vous pouvez prédéfinir un tuple, vous n'avez donc pas à les retaper plusieurs fois.

#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

REMARQUES:

  1. Si vous devez également intercepter d'autres exceptions que celles du tuple prédéfini, vous devrez en définir un autre sauf le bloc.

  2. Si vous ne pouvez tout simplement pas tolérer une variable globale, définissez-la dans main () et passez-la où vous le souhaitez ...

barbe blanche
la source
17

L'une des façons de le faire est ..

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. 

et une autre façon est de créer une méthode qui exécute la tâche exécutée par exceptbloc et de l'appeler à travers tout le exceptbloc que vous écrivez.

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]

Je sais que le second n'est pas la meilleure façon de le faire, mais je montre juste un certain nombre de façons de faire cette chose.

M.Usman
la source
J'utilise la seconde parce que j'ai deux exceptions différentes qui doivent chacune être traitées différemment. Y a-t-il quelque chose de mal à le faire de cette façon?
majikman
@majikman La deuxième méthode avec plusieurs clauses appelant chacune la même fonction n'est pas la meilleure lorsque vous essayez de ne pas vous répéter et de faire la même chose pour deux exceptions. (Voir les autres réponses pour la bonne façon de le faire). Cependant, avoir plusieurs exceptclauses est normal lorsque vous souhaitez gérer les exceptions différemment.
Éponyme du