À propos de la capture de N'IMPORTE QUELLE exception

696

Comment puis-je écrire un bloc try/ exceptqui intercepte toutes les exceptions?

user469652
la source
4
Dans la plupart des cas, vous vous trompez probablement si vous essayez d'attraper une exception. Je veux dire que vous pouvez simplement mal orthographier quelque chose dans votre code et vous ne le saurez même pas. Il est recommandé de détecter des exceptions spécifiques.
vwvolodya
12
Pour être plus précis, intercepter toutes les exceptions possibles n'est un problème que si elles sont interceptées en silence. Il est difficile de penser à quel autre endroit cette approche est appropriée, à part où les messages d'erreur capturés sont imprimés sys.stderret éventuellement enregistrés. Il s'agit d'une exception parfaitement valable et courante.
Evgeni Sergeev
avez-vous essayé try: whatever() except Exception as e: exp_capture() :?
Charlie Parker

Réponses:

564

Vous pouvez mais vous ne devriez probablement pas:

try:
    do_something()
except:
    print "Caught it!"

Cependant, cela entraînera également des exceptions comme KeyboardInterruptet vous ne le souhaitez généralement pas, n'est-ce pas? Sauf si vous relancez l'exception immédiatement - voir l'exemple suivant dans la documentation :

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise
Tim Pietzcker
la source
15
Votre dernière déclaration n'est pas vraie, vous devez dire explicitement except Exception:le nu, sauf que vous y trouverez également les exceptions BaseException.
Pykler
7
Vous devriez vraiment imprimer sur stderr.
nyuszika7h
41
Je suis très très fortement en désaccord avec la déclaration «ne devrait pas». Vous devez le faire avec parcimonie. Il y a des moments où vous avez affaire à des bibliothèques tierces (parfois chargées dynamiquement !!) qui sont devenues complètement folles avec des exceptions et les retrouver toutes peut être une tâche très douloureuse, et si vous en manquez une, vous en avez une très très énorme bogue douloureux dans votre système. Cela étant dit, il est bon d'en rechercher autant que possible et de les gérer de manière appropriée, puis de disposer d'une sauvegarde pour tous ceux que vous manquez.
Blaze
26
Ce que je trouve également étrange, c'est que dans un langage de frappe de canard où vous ne déclarez pas de variables d'instance, il est soudain très préoccupé de ne pas taper toutes vos exceptions. Hum!
Blaze
835

Mis à part une simple except:clause (que d'autres ont dit que vous ne devriez pas utiliser), vous pouvez simplement attraper Exception:

import traceback
import logging

try:
    whatever()
except Exception as e:
    logging.error(traceback.format_exc())
    # Logs the error appropriately. 

Vous ne devriez normalement envisager de le faire au niveau le plus externe de votre code que si, par exemple, vous vouliez gérer des exceptions non détectées avant de terminer.

L'avantage de except Exceptionla mise à nu exceptest qu'il y a quelques exceptions qu'il n'attrapera pas, le plus évidemment KeyboardInterruptet SystemExit: si vous les attrapez et les avalez, vous pouvez rendre difficile la sortie de votre script.

Duncan
la source
J'avais la même chose dans mon esprit, mais c'est un inconvénient, supposons que ce sont deux erreurs quand une fois est intercepté et et sauf que vous imprimez, vous sortirez du bloc d'essai et vous ne connaîtrez jamais la deuxième erreur. .
6
Pour tous ceux qui se demandent, totalement contraire à mes attentes, cela attrapera toujours des sous-classes sans exception comme les entiers, au moins en python 2.x.
Joseph Garvin
5
@JosephGarvin, c'est incorrect, c'est-à-dire que cela n'attrapera pas les "non-exceptions" qui ne font pas partie de la sous-classe Exception. Notez qu'il est impossible de intdéclencher une exception, et tenter de le faire déclenche une TypeErrorexception, ce qui serait intercepté par la except Exceptionclause englobante dans un tel cas. D'un autre côté, une classe à l'ancienne peut être élevée et qualifiée de "non-exception" qui ne fait pas partie de la sous Exception- classe - elle sera interceptée par une exceptclause nue mais pas par une except Exceptionclause.
Yoel
4
@JosephGarvin consultez cette entrée de blog: chris-lamb.co.uk/posts/no-one-expects-string-literal-exception Je suis avec @Yoel sur celui-ci, vos tests ont simplement masqué leTypeError
Duncan
2
@CharlieParker n'a rien de mal à les attraper si c'est ce que vous voulez mais ce n'est généralement pas le cas. Appeler sys.exit()signifie généralement que vous vous attendez à ce que l'application se termine, mais si vous interceptez SystemExit, cela ne se fera pas. De même, si vous appuyez sur Ctrl-C sur un script en cours d'exécution (Ctrl-break sur Windows), vous vous attendez à ce que le programme s'arrête, ne capture pas l'erreur et continue. Mais vous pouvez intercepter l'un ou les deux si vous souhaitez effectuer un nettoyage avant d'exister.
Duncan
100

Vous pouvez le faire pour gérer les exceptions générales

try:
    a = 2/0
except Exception as e:
    print e.__doc__
    print e.message
vwvolodya
la source
8
Cela peut ne pas intercepter toutes les exceptions, car la classe de base pour toutes les exceptions est BaseException et j'ai rencontré du code de production qui ne fait pas partie de la famille de classes Exception. Voir docs.python.org/3/library/… pour plus de détails à ce sujet.
DDay
4
Cela ne prend pas toutes les exceptions.
Andy_A̷n̷d̷y̷
6
Techniquement, il devrait intercepter toutes les exceptions qui ne sortent pas du système. À partir des documents @DDay liés: " exception BaseException: la classe de base pour toutes les exceptions intégrées. Elle n'est pas destinée à être directement héritée par les classes définies par l'utilisateur (pour cela, utilisez Exception)." Sauf si vous travaillez avec du code qui l'ignore, ou si vous devez intercepter des exceptions de sortie du système, ce qui précède devrait être correct à utiliser.
Peter Cassetta
@PeterCassetta quand voudrait-on intercepter les exceptions de sortie du système? Il semble que le fil conducteur de la question soit que nous ne voulons pas les attraper, mais je ne comprends pas pourquoi. Pourquoi pas d'habitude?
Charlie Parker
68

Pour intercepter toutes les exceptions possibles, interceptez BaseException . C'est au-dessus de la hiérarchie des exceptions:

Python 3: https://docs.python.org/3.5/library/exceptions.html#exception-hierarchy

Python 2.7: https://docs.python.org/2.7/library/exceptions.html#exception-hierarchy

try:
    something()
except BaseException as error:
    print('An exception occurred: {}'.format(error))

Mais comme d'autres personnes l'ont mentionné, vous n'en auriez généralement pas besoin, uniquement pour des cas spécifiques.

gitaarik
la source
1
Souhaitez-vous enregistrer la progression d'un travail de longue durée après avoir appuyé sur Ctrl-C si inhabituel?
BallpointBen
54

Exemple très simple, similaire à celui trouvé ici:

http://docs.python.org/tutorial/errors.html#defining-clean-up-actions

Si vous essayez d'attraper TOUTES les exceptions, placez tout votre code dans l'instruction "try:", à la place de "print". Exécution d'une action qui peut lever une exception. "".

try:
    print "Performing an action which may throw an exception."
except Exception, error:
    print "An exception was thrown!"
    print str(error)
else:
    print "Everything looks great!"
finally:
    print "Finally is called directly after executing the try statement whether an exception is thrown or not."

Dans l'exemple ci-dessus, vous verriez la sortie dans cet ordre:

1) Effectuer une action qui peut déclencher une exception.

2) Enfin, est appelé directement après l'exécution de l'instruction try, qu'une exception soit levée ou non.

3) "Une exception a été levée!" ou "Tout a l'air génial!" selon qu'une exception a été levée.

J'espère que cela t'aides!

Joshua Burns
la source
26

Il existe plusieurs façons de le faire en particulier avec Python 3.0 et supérieur

Approche 1

C'est une approche simple mais non recommandée car vous ne savez pas exactement quelle ligne de code lève réellement l'exception:

def bad_method():
    try:
        sqrt = 0**-1
    except Exception as e:
        print(e)

bad_method()

Approche 2

Cette approche est recommandée car elle fournit plus de détails sur chaque exception. Il comprend:

  • Numéro de ligne pour votre code
  • Nom de fichier
  • L'erreur réelle de manière plus verbeuse

Le seul inconvénient est que tracback doit être importé.

import traceback

def bad_method():
    try:
        sqrt = 0**-1
    except Exception:
        print(traceback.print_exc())

bad_method()
grepit
la source
21

Je viens de découvrir cette petite astuce pour tester si les noms d'exception dans Python 2.7. Parfois, j'ai géré des exceptions spécifiques dans le code, j'ai donc eu besoin d'un test pour voir si ce nom se trouve dans une liste d'exceptions gérées.

try:
    raise IndexError #as test error
except Exception as e:
    excepName = type(e).__name__ # returns the name of the exception
Danilo
la source
2
try:
    whatever()
except:
    # this will catch any exception or error

Il convient de mentionner qu'il ne s'agit pas d'un codage Python approprié. Cela entraînera également de nombreuses erreurs que vous ne voudrez peut-être pas détecter.

Yuval Adam
la source
il suffit d'utiliser sauf ne pas mettre en cache toutes les exceptions comme mentionné dans certaines autres réponses. Vous devez utiliser BaseException à cette fin, mais comme vous l'avez dit, personne ne devrait intercepter toutes les exceptions comme celle-ci. Je suppose que c'est bon pour commencer si le but est d'ajouter plus de granularité sauf pendant le développement mais je ne pense pas que ce sera ...
Pyglouthon