Je sais que si je veux relancer une exception, j’utilise simplement raise
sans arguments dans le bloc except
correspondant. Mais étant donné une expression imbriquée comme
try:
something()
except SomeError as e:
try:
plan_B()
except AlsoFailsError:
raise e # I'd like to raise the SomeError as if plan_B()
# didn't raise the AlsoFailsError
comment puis-je re-augmenter le SomeError
sans casser la trace de la pile? raise
seul aurait dans ce cas ré-augmenter le plus récent AlsoFailsError
. Ou comment pourrais-je refactoriser mon code pour éviter ce problème?
Vous pouvez stocker le type, la valeur et la traceback de l'exception dans des variables locales et utiliser la forme à trois arguments de raise
:
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
raise t, v, tb
Dans Python 3, la trace est stockée dans l'exception, donc raise e
va faire (principalement) la bonne chose:
try:
something()
except SomeError as e:
try:
plan_B()
except AlsoFailsError:
raise e
Le seul problème avec ce qui précède est qu’elle produira un traçage légèrement trompeur qui vous indiquera que SomeError
s’est produit lors du traitement de AlsoFailsError
(à cause de raise e
à l'intérieur except AlsoFailsError
), où l’inverse presque exact s’est produit - nous avons géré AlsoFailsError
tout en essayant de récupérer de SomeError
. Pour désactiver ce comportement et obtenir une trace qui ne mentionne jamais AlsoFailsError
, remplacez raise e
avec raise e from None
.
Même si le solution acceptée est correct, il est bon de pointer sur la bibliothèque Six qui a Python 2 + 3, en utilisant - six.reraise
.
six. relancer ( exc_type , exc_value , exc_traceback = None)
Relancez une exception, éventuellement avec un retraçage différent. [...]
Donc, vous pouvez écrire:
import six
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
six.reraise(t, v, tb)
Selon suggestion de Drew McGowen , mais en prenant en compte un cas général (où une valeur de retour s
est présente), voici une alternative à réponse de l'utilisateur4815162342 :
try:
s = something()
except SomeError as e:
def wrapped_plan_B():
try:
return False, plan_B()
except:
return True, None
failed, s = wrapped_plan_B()
if failed:
raise
Python 3.5+ associe néanmoins les informations de trace à l'erreur, il n'est donc plus nécessaire de les enregistrer séparément.
>>> def f():
... try:
... raise SyntaxError
... except Exception as e:
... err = e
... try:
... raise AttributeError
... except Exception as e1:
... raise err from None
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in f
File "<stdin>", line 3, in f
SyntaxError: None
>>>