Comment puis-je déclencher une exception en Python afin qu'elle puisse plus tard être interceptée via un except
bloc?
Comment lancer / lever manuellement une exception en Python?
Soyez précis dans votre message, par exemple:
raise ValueError('A very specific bad thing happened.')
Évitez d'élever un générique Exception
. Pour l'attraper, vous devrez attraper toutes les autres exceptions plus spécifiques qui le sous-classent.
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
Par exemple:
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',)
Et les captures plus spécifiques n'attraperont pas l'exception générale:
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
déclarationraise ValueError('A very specific bad thing happened')
ce qui permet également de transmettre un nombre arbitraire d'arguments au constructeur:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
Ces arguments sont accessibles par l' args
attribut sur l' Exception
objet. Par exemple:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
impressions
('message', 'foo', 'bar', 'baz')
Dans Python 2.5, un message
attribut réel a été ajouté pour BaseException
encourager les utilisateurs à sous-classer les exceptions et à cesser d'utiliser args
, mais l'introduction message
et la dépréciation d'origine des arguments ont été retirées .
except
clauseLorsque vous êtes dans une clause except, vous souhaiterez peut-être, par exemple, enregistrer qu'un type d'erreur spécifique s'est produit, puis sur-relancer. La meilleure façon de le faire tout en préservant la trace de pile est d'utiliser une instruction de relance nue. Par exemple:
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!
Vous pouvez conserver le stacktrace (et la valeur d'erreur) avec sys.exc_info()
, mais c'est beaucoup plus sujet aux erreurs et a des problèmes de compatibilité entre Python 2 et 3 , préférez utiliser un bare raise
pour relancer.
Pour expliquer - le sys.exc_info()
retourne le type, la valeur et traceback.
type, value, traceback = sys.exc_info()
C'est la syntaxe de Python 2 - notez que ce n'est pas compatible avec 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]
Si vous le souhaitez, vous pouvez modifier ce qui se passe avec votre nouvelle augmentation - par exemple, définir un nouveau args
pour l'instance:
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
Et nous avons conservé l'intégralité de la trace en modifiant les arguments. Notez que ce n'est pas une meilleure pratique et que c'est une syntaxe invalide dans Python 3 (ce qui rend la compatibilité beaucoup plus difficile à contourner).
>>> 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>
En Python 3 :
raise error.with_traceback(sys.exc_info()[2])
Encore une fois: évitez de manipuler manuellement les retraits. C'est moins efficace et plus sujet aux erreurs. Et si vous utilisez le filetage et que sys.exc_info
vous pouvez même obtenir le mauvais retraçage (surtout si vous utilisez la gestion des exceptions pour le flux de contrôle - ce que j'aurais tendance à éviter personnellement.)
En Python 3, vous pouvez chaîner des exceptions, qui préservent les retraits:
raise RuntimeError('specific message') from error
Être conscient:
Ceux-ci peuvent facilement se cacher et même entrer dans le code de production. Vous voulez lever une exception, et les faire lèvera une exception, mais pas celle prévue!
Valide en Python 2, mais pas en Python 3 est le suivant:
raise ValueError, 'message' # Don't do this, it's deprecated!
Uniquement valable dans les versions beaucoup plus anciennes de Python (2.4 et inférieures), vous pouvez toujours voir des gens lever des chaînes:
raise 'message' # really really wrong. don't do this.
Dans toutes les versions modernes, cela soulèvera en fait un TypeError
, car vous n'élevez pas un BaseException
type. Si vous ne recherchez pas la bonne exception et que vous n'avez pas de réviseur au courant du problème, il pourrait entrer en production.
Je lève des exceptions pour avertir les consommateurs de mon API s'ils ne l'utilisent pas correctement:
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)))
"Je veux faire une erreur exprès, pour que ça aille dans l'exception"
Vous pouvez créer vos propres types d'erreur, si vous souhaitez indiquer que quelque chose de spécifique ne va pas avec votre application, il suffit de sous-classer le point approprié dans la hiérarchie des exceptions:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
et utilisation:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
raise
est ce dont j'avais besoin pour pouvoir effectuer un débogage d'erreur personnalisé à plusieurs niveaux d'exécution de code sans interrompre la trace de la pile.raise sys.exc_info()[0], (sys.exc_info()[1], my_extra_info), sys.exc_info()[2]
semble faire ce que je veux, et je n'ai jamais rencontré de problèmes avec ça. Mais cela semble hacky et pas une pratique acceptée. Y a-t-il une meilleure façon?Exception
votre classe parent - vous pouvez sous-classer quelque chose de plus spécifique, et devriez le faire si cela a du sens.AppError
exception non définie . Il peut être préférable d'utiliser une erreurAttributeError
Impossible d'obtenir beaucoup plus de pythonic que cela:
Voir les documents d'instructions raise pour python si vous souhaitez plus d'informations.
la source
En Python3, il existe 4 syntaxes différentes pour éliminer les exceptions:
Si vous utilisez
raise exception (args)
pour déclencher une exception, leargs
sera imprimé lorsque vous imprimerez l'objet d'exception - comme illustré dans l'exemple ci-dessous.raise
sans aucun argument relance la dernière exception. Ceci est utile si vous devez effectuer certaines actions après avoir intercepté l'exception et que vous souhaitez ensuite la relancer. Mais s'il n'y avait pas d'exception auparavant, l'raise
instruction déclencheTypeError
Exception.Cette instruction est utilisée pour créer un chaînage d'exceptions dans lequel une exception déclenchée en réponse à une autre exception peut contenir les détails de l'exception d'origine, comme illustré dans l'exemple ci-dessous.
Production:
la source
exception(args)
plusexception (args)
raise exception(args) from None
dire que l'exception actuellement active a été gérée et ne présente plus d'intérêt. Sinon, si vous déclenchez une exception dans unexcept
bloc et qu'elle n'est pas gérée, les retraits pour les deux exceptions seront affichés séparés par le message «Pendant la gestion de l'exception ci-dessus, une autre exception s'est produite»Pour le cas courant où vous devez lever une exception en réponse à des conditions inattendues et que vous n'avez jamais l'intention d'attraper, mais simplement d'échouer rapidement pour vous permettre de déboguer à partir de là si cela se produit - la plus logique semble être
AssertionError
:la source
ValueError
queAssertionError
parce qu'il n'y a pas de problème avec une assertion (car aucun n'est fait ici) - le problème est avec une valeur. Si vous voulez vraiment unAssertionError
dans ce cas, écrivezassert distance > 0, 'Distance must be positive'
. Mais vous ne devriez pas vérifier les erreurs de cette façon car les assertions peuvent être désactivées (python -O
).-O
.Lisez d'abord les réponses existantes, ce n'est qu'un addendum.
Notez que vous pouvez déclencher des exceptions avec ou sans arguments.
Exemple:
quitte le programme mais vous voudrez peut-être savoir ce qui s'est passé. Vous pouvez donc l'utiliser.
cela affichera "programme quitté" sur stderr avant de fermer le programme.
la source
raise SystemExit()
le meilleur choix? Pourquoi le premier fonctionne-t-il même?Une autre façon de lever une exception est
assert
. Vous pouvez utiliser assert pour vérifier qu'une condition est remplie sinon, elle augmenteraAssertionError
. Pour plus de détails jetez un œil ici .la source
Juste pour noter: il y a des moments où vous voulez gérer les exceptions génériques. Si vous traitez un tas de fichiers et enregistrez vos erreurs, vous souhaiterez peut-être intercepter toute erreur qui se produit pour un fichier, l'enregistrer et continuer à traiter le reste des fichiers. Dans ce cas, un
bloquer une bonne façon de le faire. Vous voudrez toujours
raise
des exceptions spécifiques afin que vous sachiez ce qu'elles signifient, cependant.la source
Vous devriez apprendre l'instruction raise de python pour cela. Il doit être conservé à l'intérieur du bloc try. Exemple -
la source