Ich möchte den Namen des Fehlers und die Traceback-Details in einer Variablen speichern. Hier ist mein Versuch.
import sys
try:
try:
print x
except Exception, ex:
raise NameError
except Exception, er:
print "0", sys.exc_info()[0]
print "1", sys.exc_info()[1]
print "2", sys.exc_info()[2]
Ausgabe:
0 <type 'exceptions.NameError'>
1
2 <traceback object at 0xbd5fc8>
Gewünschte Ausgabe:
0 NameError
1
2 Traceback (most recent call last):
File "exception.py", line 6, in <module>
raise NameError
P.S. Ich weiß, dass dies mit dem Traceback-Modul problemlos möglich ist, aber ich möchte hier die Verwendung des Objekts sys.exc_info () [2] kennen.
So mache ich es:
>>> import traceback
>>> try:
... int('k')
... except:
... var = traceback.format_exc()
...
>>> print var
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ValueError: invalid literal for int() with base 10: 'k'
Sie sollten sich jedoch die traceback-Dokumentation anschauen, da es möglicherweise geeignetere Methoden gibt, je nachdem, wie Sie Ihre Variable anschließend bearbeiten möchten ...
sys.exc_info () gibt ein Tuple mit drei Werten (type, value, traceback) zurück.
Zum Beispiel im folgenden Programm
try:
a = 1/0
except Exception,e:
exc_Tuple = sys.exc_info()
Wenn wir nun den Tupel drucken, werden dies die Werte sein.
Die obigen Details können auch abgerufen werden, indem die Ausnahme einfach im Zeichenfolgenformat gedruckt wird.
print str(e)
Verwenden Sie traceback.extract_stack()
, wenn Sie bequem auf Modulnamen, Funktionsnamen und Leitungsnummern zugreifen möchten.
Verwenden Sie ''.join(traceback.format_stack())
, wenn Sie nur eine Zeichenfolge wünschen, die wie die Ausgabe von traceback.print_stack()
aussieht.
Beachten Sie, dass Sie auch mit ''.join()
einen mehrzeiligen String erhalten, da die Elemente von format_stack()
\n
enthalten. Siehe Ausgabe unten.
Denken Sie an import traceback
.
Hier ist die Ausgabe von traceback.extract_stack()
. Formatierung zur besseren Lesbarkeit hinzugefügt.
>>> traceback.extract_stack()
[
('<string>', 1, '<module>', None),
('C:\\Python\\lib\\idlelib\\run.py', 126, 'main', 'ret = method(*args, **kwargs)'),
('C:\\Python\\lib\\idlelib\\run.py', 353, 'runcode', 'exec(code, self.locals)'),
('<pyshell#1>', 1, '<module>', None)
]
Hier ist die Ausgabe von ''.join(traceback.format_stack())
. Formatierung zur besseren Lesbarkeit hinzugefügt.
>>> ''.join(traceback.format_stack())
' File "<string>", line 1, in <module>\n
File "C:\\Python\\lib\\idlelib\\run.py", line 126, in main\n
ret = method(*args, **kwargs)\n
File "C:\\Python\\lib\\idlelib\\run.py", line 353, in runcode\n
exec(code, self.locals)\n File "<pyshell#2>", line 1, in <module>\n'
Seien Sie vorsichtig, wenn Sie das Exception-Objekt oder das Traceback-Objekt aus dem Exception-Handler entfernen, da dies zu Zirkelverweisen führt und gc.collect()
das Sammeln nicht durchführen kann. Dies scheint ein besonderes Problem in der Notebook-Umgebung ipython/jupyter zu sein, bei dem das Traceback-Objekt nicht zur richtigen Zeit gelöscht wird und selbst ein expliziter Aufruf von gc.collect()
im Abschnitt finally
nichts bewirkt. Und das ist ein riesiges Problem, wenn Sie einige große Objekte haben, deren Speicher dadurch nicht wiederhergestellt werden (z. B. CUDA hat nicht genügend Arbeitsspeicher, mit Ausnahme, dass diese Lösung keinen vollständigen Kernel-Neustart erfordert, um wiederhergestellt zu werden).
Wenn Sie das Traceback-Objekt speichern möchten, müssen Sie es in der Regel aus den Verweisen auf locals()
entfernen.
import sys, traceback, gc
type, val, tb = None, None, None
try:
myfunc()
except:
type, val, tb = sys.exc_info()
traceback.clear_frames(tb)
# some cleanup code
gc.collect()
# and then use the tb:
if tb:
raise type(val).with_traceback(tb)
Im Fall eines Jupyter-Notebooks müssen Sie dies zumindest im Ausnahmehandler tun:
try:
myfunc()
except:
type, val, tb = sys.exc_info()
traceback.clear_frames(tb)
raise type(val).with_traceback(tb)
finally:
# cleanup code in here
gc.collect()
Getestet mit Python 3.7.
p.s. Das Problem mit ipython oder jupyter notebook env ist, dass es %tb
magic hat, das den Traceback speichert und später wieder verfügbar macht. Daher wird jede locals()
in allen an dem Traceback beteiligten Frames nicht freigegeben, bis das Notebook beendet wird oder eine andere Ausnahme die zuvor gespeicherte Rückverfolgung überschreibt. Das ist sehr problematisch. Es sollte das Traceback nicht speichern, ohne seine Frames zu säubern. Fix eingereicht hier .
Das Objekt kann als Parameter in der Funktion Exception.with_traceback()
verwendet werden:
except Exception as e:
tb = sys.exc_info()
print(e.with_traceback(tb[2]))