La réponse à cette question dépend de la version de Python que vous utilisez.
Dans Python 3
C'est simple: les exceptions sont équipées d'un __traceback__
attribut qui contient le traçage. Cet attribut est également accessible en écriture et peut être facilement défini à l'aide de la with_traceback
méthode des exceptions:
raise Exception("foo occurred").with_traceback(tracebackobj)
Ces fonctionnalités sont décrites de manière minimale dans le cadre de la raise
documentation.
Tout le mérite de cette partie de la réponse doit revenir à Vyctor, qui a publié cette information en premier . Je l'inclus ici uniquement parce que cette réponse est bloquée en haut et que Python 3 est de plus en plus courant.
Dans Python 2
C'est extrêmement complexe. Le problème avec les retraits est qu'ils ont des références aux cadres de pile, et les cadres de pile ont des références aux retraçages qui ont des références aux cadres de pile qui ont des références à ... vous voyez l'idée. Cela provoque des problèmes pour le garbage collector. (Merci à ecatmur d' avoir d'abord signalé cela.)
La bonne façon de résoudre ce problème serait de rompre chirurgicalement le cycle après avoir quitté la except
clause, ce que fait Python 3. La solution Python 2 est beaucoup plus moche: vous disposez d'une fonction ad-hoc sys.exc_info()
, qui ne fonctionne qu'à l'intérieur de la except
clause . Il retourne un tuple contenant l'exception, le type d'exception et la trace de toute exception actuellement gérée.
Donc, si vous êtes à l'intérieur de la except
clause, vous pouvez utiliser la sortie de sys.exc_info()
avec le traceback
module pour faire diverses choses utiles:
>>> import sys, traceback
>>> def raise_exception():
... try:
... raise Exception
... except Exception:
... ex_type, ex, tb = sys.exc_info()
... traceback.print_tb(tb)
... finally:
... del tb
...
>>> raise_exception()
File "<stdin>", line 3, in raise_exception
Mais comme votre modification l'indique, vous essayez d'obtenir le traçage qui aurait été imprimé si votre exception n'avait pas été gérée, après l'avoir déjà gérée. C'est une question beaucoup plus difficile. Malheureusement, sys.exc_info
retourne (None, None, None)
lorsqu'aucune exception n'est gérée. D'autres sys
attributs connexes n'aident pas non plus. sys.exc_traceback
est obsolète et indéfinie lorsqu'aucune exception n'est gérée; sys.last_traceback
semble parfait, mais il ne semble être défini que lors de sessions interactives.
Si vous pouvez contrôler la manière dont l'exception est déclenchée, vous pourrez peut-être utiliser inspect
une exception personnalisée pour stocker certaines des informations. Mais je ne suis pas tout à fait sûr de savoir comment cela fonctionnerait.
Pour dire la vérité, attraper et renvoyer une exception est quelque chose d'inhabituel à faire. Cela pourrait être un signe que vous devez de toute façon refactoriser.