Comment relancer une exception dans try/excepté les blocs imbriqués?
je sais que si je veux relancer une exception, Je l'utilise simplement raise
sans arguments dans le bloc respectif except
. Mais avec 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 relancer le SomeError
sans briser la trace de la pile? raise
relèverait dans ce cas le plus récent AlsoFailsError
. Ou comment puis-je modifier mon code pour éviter ce problème?
4 réponses
vous pouvez stocker le type d'exception, la valeur, et traceback dans les variables locales et utiliser le forme à trois arguments de raise
:
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
raise t, v, tb
en Python 3 le traceback est stocké dans l'exception, donc raise e
fera la (la plupart du temps) 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'il va produire un traceback légèrement trompeur qui vous dit que SomeError
s'est produit alors que manipulation AlsoFailsError
(à cause de raise e
à l'intérieur de Except AlsoFailsError
), où en fait le contraire presque exact s'est produit - nous avons manipulé AlsoFailsError
tout en essayant de récupérer de SomeError
. Pour désactiver ce comportement et obtenir un traceback qui ne mentionne jamais AlsoFailsError
, remplacer raise e
par raise e from None
.
comme pour suggestion de Drew McGowen , mais en prenant soin d'un cas général (où une valeur de retour s
est présent), voici une alternative à réponse de l'utilisateur 4815162342 :
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
même si la solution acceptée est correcte, il est bon de pointer vers la bibliothèque Six qui a une solution Python 2+3, en utilisant six.reraise
.
de six. relancer ( exc_type , exc_value , exc_traceback =None)
Relancer une exception, éventuellement, de avec un traceback 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)
Python 3.5+ attache l'information de retraçage à l'erreur de toute façon, il n'est donc plus nécessaire de la sauvegarder 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
>>>