Wie speichere traceback / sys.exc_info () Werte in einer Variablen?

126

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

PS Ich weiß, dass dies mit dem Traceback-Modul einfach möglich ist, aber ich möchte die Verwendung des Objekts sys.exc_info () [2] hier kennen.

codersofthedark
quelle
Haben Sie versucht, sys.exc_info () [x] .__ str __ () zu drucken?
Zmbq
3
Möglicherweise haben Sie falsch verstanden, was in Ihrem Programm vor sich geht: Was Sie als "sys.exc_info () [2] -Objekt" bezeichnen, ist eine Instanz des Traceback-Objekts (= Sie verwenden das Traceback-Modul bereits). Jetzt können Sie dieses Objekt bearbeiten, ohne die Hilfsfunktionen im Traceback-Modul zu verwenden. Dies ändert jedoch nichts an der Tatsache, dass Sie es noch verwenden. :)
Mac
1
@Mac, bitte helfen Sie mir, mit oder ohne Verwendung der Hilfsfunktion auf den Wert dieses Objekts zuzugreifen.
codersofthedark
1
@dragosrsupercool - Wie ich in meiner Antwort unten erwähnt habe, sollten Sie sich die Traceback-Dokumentation ansehen . Ich habe ein Beispiel für das Abrufen der Daten in Textform bereitgestellt, aber es gibt auch andere Methoden des Objekts, mit denen Sie den Ausnahmenamen, die Codezeile usw. extrahieren können. Die richtige hängt wirklich davon ab, wie Sie die Daten bearbeiten möchten Wert danach ...
Mac
1
Meine Antwort auf eine andere Frage kann helfen, die Details zu veranschaulichen - mit Links! Für vordefinierte Zeichenfolgen scheint das Standard-Bibliotheks-Traceback-Modul in Ordnung zu sein. Wenn Sie die Details erhalten möchten, lesen Sie die Quelle ( <python install path>/Lib/traceback.py) für weitere Informationen.
Pythonlarry

Antworten:

180

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 ansehen , da Sie dort möglicherweise geeignetere Methoden finden, je nachdem, wie Sie Ihre Variable anschließend verarbeiten möchten ...

Mac
quelle
1
Ich suchte nach einer Methode ohne Traceback-Modul. Gibt es eine Möglichkeit, dass wir nur Rückverfolgungsdetails aus dieser Objektreferenz drucken können? sys.exc_info () [2]
codersofthedark
Richtig, deshalb dachte ich, wir könnten so etwas wie sys.exc_info () [2] .format_exc () machen, aber das funktioniert nicht. Daher frage ich mich, wie ich Wert aus dem Trace-Back-Objekt sys.exc_info () extrahieren kann. [2]. Irgendeine Idee?
Codersofthedark
1
sys.exc_info () [2] .tb_text gibt folgenden Fehler aus -> AttributeError: 'traceback'-Objekt hat kein Attribut' tb_text '
codersofthedark
4
@dragosrsupercool - sys.exc_info()[2].tb_frame.f_code.co_names[3], aber es macht überhaupt keinen Sinn ... Wenn es ein Modul gibt, das tracebackin der Standardbibliothek aufgerufen wird , gibt es einen Grund dafür ... :)
mac
2
@codersofthedark traceback.format_exception(*sys.exc_info())ist der Weg, es zu tun. Aber das ist funktional gleichbedeutend mit traceback.format_exc().
wizzwizz4
25

sys.exc_info () gibt ein Tupel mit drei Werten zurück (Typ, Wert, Rückverfolgung).

  1. Hier erhält type den Ausnahmetyp der Ausnahme, die behandelt wird
  2. value sind die Argumente, die an den Konstruktor der Ausnahmeklasse übergeben werden
  3. Traceback enthält die Stapelinformationen, z. B. wo die Ausnahme aufgetreten ist usw.

Zum Beispiel im folgenden Programm

try:

    a = 1/0

except Exception,e:

    exc_tuple = sys.exc_info()

Wenn wir nun das Tupel drucken, sind dies die Werte.

  1. Der Wert für exc_tuple [0] ist " ZeroDivisionError ".
  2. Der Wert für exc_tuple [1] ist " Ganzzahldivision oder Modulo durch Null " (Zeichenfolge, die als Parameter an die Ausnahmeklasse übergeben wird).
  3. Der Wert für exc_tuple [2] ist " Trackback-Objekt bei (eine Speicheradresse) ".

Die obigen Details können auch durch einfaches Drucken der Ausnahme im Zeichenfolgenformat abgerufen werden.

print str(e)
keya
quelle
Für Python3 ist exc_tuple [1] (auch bekannt als Wert) die Instanz der Ausnahme, nicht der als Parameter übergebene String. Siehe: docs.python.org/3/library/sys.html#sys.exc_info
Jinghao Shi
Sollte es nicht "außer Ausnahme als e:" sein?
Henrik vor
20

Verwenden traceback.extract_stack()Sie diese Option, wenn Sie bequem auf Modul- und Funktionsnamen sowie Zeilennummern zugreifen möchten.

Verwenden ''.join(traceback.format_stack())Sie diese Option, wenn Sie nur eine Zeichenfolge möchten, die der traceback.print_stack()Ausgabe ähnelt.

Beachten Sie, dass auch bei ''.join()Ihnen eine mehrzeilige Zeichenfolge angezeigt wird, da die Elemente von format_stack()enthalten sind \n. Siehe Ausgabe unten.

Denken Sie daran 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'
Nathan
quelle
4

Seien Sie vorsichtig, wenn Sie das Ausnahmeobjekt oder das Traceback-Objekt aus dem Ausnahmebehandler entfernen, da dies zu Zirkelverweisen führt und gc.collect()nicht erfasst werden kann. Dies scheint ein besonderes Problem in der ipython / jupyter-Notebook-Umgebung zu sein, in der das Traceback-Objekt nicht zum richtigen Zeitpunkt gelöscht wird und sogar explizit aufgerufen wirdgc.collect() in finallysection nichts bewirkt. Und das ist ein großes Problem, wenn Sie einige große Objekte haben, deren Speicher aus diesem Grund nicht zurückgefordert wird (z. B. CUDA-Ausnahmen für nicht genügend Speicher, für die ohne diese Lösung ein vollständiger Kernel-Neustart erforderlich ist).

Wenn Sie das Traceback-Objekt speichern möchten, müssen Sie es im Allgemeinen aus Verweisen auf Folgendes löschen locals():

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 Falle eines Jupyter-Notebooks müssen Sie dies zumindest im Ausnahmebehandler 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.

ps das problem mit ipython oder jupyter notebook env ist, dass es magie hat, %tbdie den traceback speichert und ihn zu jedem späteren zeitpunkt verfügbar macht. Infolgedessen werden locals()alle Frames, die am Traceback teilnehmen, erst freigegeben, wenn das Notebook beendet wird oder eine andere Ausnahme die zuvor gespeicherte Rückverfolgung überschreibt. Das ist sehr problematisch. Der Traceback sollte nicht ohne Reinigung der Frames gespeichert werden. Fix hier eingereicht .

Stason
quelle
3

Das Objekt kann als Parameter in der Exception.with_traceback()Funktion verwendet werden:

except Exception as e:
    tb = sys.exc_info()
    print(e.with_traceback(tb[2]))
Hansen D'Silva
quelle