Die Antwort auf diese Frage hängt von der verwendeten Python-Version ab.
In Python 3
Es ist ganz einfach: Ausnahmen sind mit einem __traceback__
Attribut ausgestattet, das den Traceback enthält. Dieses Attribut ist auch beschreibbar und kann bequem mithilfe der with_traceback
Ausnahmemethode festgelegt werden:
raise Exception("foo occurred").with_traceback(tracebackobj)
Diese Funktionen werden in der raise
Dokumentation nur minimal beschrieben .
Alle Gutschriften für diesen Teil der Antwort sollten an Vyctor gehen, der diese Informationen zuerst veröffentlicht hat . Ich füge es hier nur ein, weil diese Antwort oben feststeckt und Python 3 immer häufiger wird.
In Python 2
Es ist ärgerlich komplex. Das Problem mit Tracebacks ist, dass sie Verweise auf Stapelrahmen haben und Stapelrahmen Verweise auf die Rückverfolgungen haben, die Verweise auf Stapelrahmen haben , die Verweise auf ... Sie haben die Idee. Dies verursacht Probleme für den Garbage Collector. (Vielen Dank an ecatmur für den ersten Hinweis.)
Die gute Möglichkeit, dies zu lösen, besteht darin , den Zyklus nach dem Verlassen der except
Klausel chirurgisch zu unterbrechen, wie es Python 3 tut. Die Python 2-Lösung ist viel hässlicher: Sie erhalten eine Ad-hoc-Funktion sys.exc_info()
, die nur innerhalb der except
Klausel funktioniert . Es gibt ein Tupel zurück, das die Ausnahme, den Ausnahmetyp und den Traceback für jede Ausnahme enthält, die gerade behandelt wird.
Wenn Sie sich also innerhalb der except
Klausel befinden, können Sie die Ausgabe von sys.exc_info()
zusammen mit dem traceback
Modul verwenden, um verschiedene nützliche Dinge zu tun:
>>> 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
Wie aus Ihrer Bearbeitung hervorgeht, versuchen Sie jedoch, den Traceback abzurufen, der gedruckt worden wäre, wenn Ihre Ausnahme nicht behandelt worden wäre, nachdem sie bereits behandelt wurde. Das ist eine viel schwierigere Frage. Leider sys.exc_info
gibt , (None, None, None)
wenn keine Ausnahme behandelt wird. Andere verwandte sys
Attribute helfen auch nicht. sys.exc_traceback
ist veraltet und undefiniert, wenn keine Ausnahme behandelt wird; sys.last_traceback
scheint perfekt zu sein, scheint aber nur während interaktiver Sitzungen definiert zu werden.
Wenn Sie steuern können, wie die Ausnahme ausgelöst wird, können Sie möglicherweise inspect
eine benutzerdefinierte Ausnahme verwenden , um einige der Informationen zu speichern. Aber ich bin mir nicht ganz sicher, wie das funktionieren würde.
Um die Wahrheit zu sagen, ist es ungewöhnlich, eine Ausnahme zu fangen und zurückzugeben. Dies könnte ein Zeichen dafür sein, dass Sie ohnehin umgestalten müssen.
sys.exc_info
in Verbindung mit dem Rückrufansatz, den ich für Ihre andere Frage vorschlage.Seit Python 3.0 [PEP 3109] hat die eingebaute Klasse
Exception
ein__traceback__
Attribut, das a enthälttraceback object
(mit Python 3.2.3):Das Problem ist, dass ich
__traceback__
nach einer Weile des Googelns nur wenige Artikel gefunden habe, aber keiner beschreibt, ob oder warum Sie verwenden sollten (nicht)__traceback__
.In der Python 3-Dokumentation für
raise
heißt es jedoch:Ich gehe also davon aus, dass es verwendet werden soll.
quelle
__
Name, der angibt, dass es sich um ein Implementierungsdetail handelt, nicht um eine öffentliche Eigenschaft?__foo
eine private Methode, aber__foo__
(auch mit nachgestellten Unterstrichen) eine "magische" Methode (und nicht privat).__traceback__
Attribut ist 100% sicher zu verwenden, wie Sie möchten, ohne GC-Auswirkungen. Es ist schwer, das aus der Dokumentation zu ersehen, aber ecatmur fand harte Beweise .Eine Möglichkeit, Traceback als Zeichenfolge von einem Ausnahmeobjekt in Python 3 abzurufen:
traceback.format_tb(...)
Gibt eine Liste von Zeichenfolgen zurück.''.join(...)
verbindet sie zusammen. Weitere Informationen finden Sie unter: https://docs.python.org/3/library/traceback.html#traceback.format_tbquelle
Abgesehen davon möchten Sie Folgendes, wenn Sie tatsächlich den vollständigen Traceback erhalten möchten, wie er auf Ihrem Terminal gedruckt wird.
Wenn Sie die
format_tb
obigen Antworten verwenden, erhalten Sie weniger Informationen:quelle
etype=type(exc)
kann jetzt weggelassen werden: "In Version 3.5 geändert: Das etype-Argument wird ignoriert und aus dem Werttyp abgeleitet." docs.python.org/3.7/library/… Getestet in Python 3.7.3.Es gibt einen sehr guten Grund, warum der Traceback nicht in der Ausnahme gespeichert ist. Da der Traceback Verweise auf die Lokalitäten seines Stacks enthält, würde dies zu einem Zirkelverweis und einem (vorübergehenden) Speicherverlust führen, bis der zirkuläre GC aktiviert wird. (Aus diesem Grund sollten Sie den Traceback niemals in einer lokalen Variablen speichern .)
Das Einzige,
stuff
woran ich denken kann, ist, dass Sie die Globals von monkeypatch so einstellen, dass sie, wenn sie glauben, dass sie abfangen,Exception
tatsächlich einen speziellen Typ abfangen und die Ausnahme sich an Sie als Anrufer weitergibt:quelle
e.__traceback__
.except
Blocks gemäß PEP 3110 gelöscht wird .