Réponses:
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 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 erreur AttributeError
NE FAITES PAS CELA . Élever une nue
Exception
n'est absolument pas la bonne chose à faire; voir plutôt l'excellente réponse d'Aaron Hall .
Impossible d'obtenir beaucoup plus de pythonic que cela:
raise Exception("I know python!")
Voir les documents d'instructions raise pour python si vous souhaitez plus d'informations.
En Python3, il existe 4 syntaxes différentes pour éliminer les exceptions:
1. raise exception
2. raise exception (args)
3. raise
4. raise exception (args) from original_exception
1. lever l'exception vs 2. lever l'exception (args)
Si vous utilisez raise exception (args)
pour déclencher une exception, le args
sera imprimé lorsque vous imprimerez l'objet d'exception - comme illustré dans l'exemple ci-dessous.
#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. élever
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éclenche TypeError
Exception.
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. lever l'exception (args) de original_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.
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__)
Production:
ZeroDivisionError -- division by zero
MyException Zero Division
division by zero
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 un except
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
:
if 0 < distance <= RADIUS:
#Do something.
elif RADIUS < distance:
#Do something.
else:
raise AssertionError("Unexpected value of 'distance'!", distance)
ValueError
que AssertionError
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 un AssertionError
dans ce cas, écrivez assert 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:
raise SystemExit
quitte le programme mais vous voudrez peut-être savoir ce qui s'est passé. Vous pouvez donc l'utiliser.
raise SystemExit("program exited")
cela affichera "programme quitté" sur stderr avant de fermer le programme.
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 augmentera AssertionError
. Pour plus de détails jetez un œil ici .
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))
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
try:
foo()
except Exception as e:
print(str(e)) # Print out handled error
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.
Vous devriez apprendre l'instruction raise de python pour cela. Il doit être conservé à l'intérieur du bloc try. Exemple -
try:
raise TypeError #remove TypeError by any other error if you want
except TypeError:
print('TypeError raised')
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.