1466 Stimmen

Wie kann man den vollständigen Traceback der Ausnahme abfangen und ausgeben, ohne das Programm anzuhalten/zu beenden?

Ich möchte Ausnahmen abfangen und protokollieren, ohne zu beenden, z. B.,

try:
    do_stuff()
except Exception as err:
    print(Exception, err)
    # I want to print the entire traceback here,
    # not just the exception name and details

Ich möchte genau die gleiche Ausgabe drucken, die gedruckt wird, wenn die Ausnahme ausgelöst wird, ohne dass die try/except die Ausnahme abfängt, und ich tue no Ich möchte, dass es mein Programm beendet.

17 Stimmen

Das ist zwar keine vollständige Antwort, aber vielleicht möchte jemand wissen, dass man viele Informationen erhalten kann, wenn man in err.__traceback__ (zumindest in Python 3.x)

35 Stimmen

Es wurde 825.000 Mal aufgerufen, während man versuchte, herauszufinden, wie man seine Stacktraces ausdrucken kann. Das ist ein weiteres Zen von Python.

13 Stimmen

Anscheinend bin ich der Einzige auf der Welt, der den Stapel ausdrucken möchte. wenn kein Fehler vorliegt (= nur um zu sehen, wie ich genau zu dieser Zeile gekommen bin (es ist nicht mein Code, und er ist so hässlich, dass ich nicht weiß, wie er hierher gekommen ist!)).

49voto

traceback.format_exception(exception_object)

Wenn Sie nur das Exception-Objekt haben, können Sie den Traceback als String von jedem Punkt des Codes in Python 3 mit erhalten:

import traceback

''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))

Vollständiges Beispiel:

#!/usr/bin/env python3

import traceback

def f():
    g()

def g():
    raise Exception('asdf')

try:
    g()
except Exception as e:
    exc_obj = e

tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)

Ausgabe:

Traceback (most recent call last):
  File "./main.py", line 12, in <module>
    g()
  File "./main.py", line 9, in g
    raise Exception('asdf')
Exception: asdf

Dokumentation: https://docs.python.org/3.9/library/traceback.html#traceback.format_exception

Siehe auch: Extrahieren von Traceback-Informationen aus einem Ausnahmeobjekt

Getestet in Python 3.9

12 Stimmen

Warum ist die einzige Möglichkeit, dies in der Sprache zu tun, die doppelte Übergabe derselben Information (beide exc_obj y exc_obj.__traceback__ ), und ein irrelevantes drittes Argument None ?

27voto

Mark McDonald Punkte 7208

Zusätzlich zu Aaron Hall's Antwort wenn Sie protokollieren, aber nicht die logging.exception() (da es auf der Ebene ERROR protokolliert), können Sie eine niedrigere Ebene verwenden und exc_info=True . z.B..

try:
    do_something_that_might_error()
except Exception:
    logging.info('General exception noted.', exc_info=True)

0 Stimmen

Dies ist auch gut, wenn es um einen erkannten Fehler bei der Protokollierung geht... d.h. wenn Sie aus irgendeinem Grund versäumt haben, ein aktuelles Logger-Objekt zu erstellen.

27voto

bgdnlp Punkte 863

Ich sehe das in keiner der anderen Antworten erwähnt. Wenn Sie aus irgendeinem Grund ein Exception-Objekt weitergeben...

In Python 3.5+ können Sie einen Trace von einem Exception-Objekt erhalten, indem Sie traceback.TracebackException.from_exception() . Zum Beispiel:

import traceback

def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')

def stack_lvl_2():
    try:
        stack_lvl_3()
    except Exception as e:
        # raise
        return e

def stack_lvl_1():
    e = stack_lvl_2()
    return e

e = stack_lvl_1()

tb1 = traceback.TracebackException.from_exception(e)
print(''.join(tb1.format()))

Der obige Code führt jedoch zu:

Traceback (most recent call last):
  File "exc.py", line 10, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')
Exception: ('a1', 'b2', 'c3')

Dies sind nur zwei Ebenen des Stapels, im Gegensatz zu dem, was auf dem Bildschirm ausgegeben worden wäre, wenn die Ausnahme in stack_lvl_2() und nicht abgefangen werden (entfernen Sie das Kommentarzeichen # raise Zeile).

So wie ich es verstehe, liegt das daran, dass eine Ausnahme nur den aktuellen Stand des Stacks aufzeichnet, wenn sie ausgelöst wird, stack_lvl_3() in diesem Fall. Bei der Weitergabe durch den Stapel werden weitere Ebenen zu seinem __traceback__ . Aber wir haben es abgefangen in stack_lvl_2() Das heißt, es konnten nur die Stufen 3 und 2 aufgezeichnet werden. Um die vollständige Aufzeichnung auf stdout zu erhalten, müssten wir sie auf der höchsten (niedrigsten?) Stufe abfangen:

import traceback

def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')

def stack_lvl_2():
    stack_lvl_3()

def stack_lvl_1():
    stack_lvl_2()

try:
    stack_lvl_1()
except Exception as exc:
    tb = traceback.TracebackException.from_exception(exc)

print('Handled at stack lvl 0')
print(''.join(tb.stack.format()))

Daraus ergibt sich:

Handled at stack lvl 0
  File "exc.py", line 17, in <module>
    stack_lvl_1()
  File "exc.py", line 13, in stack_lvl_1
    stack_lvl_2()
  File "exc.py", line 9, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')

Beachten Sie, dass der Stapeldruck anders ist, die erste und die letzte Zeile fehlen. Da es sich um eine diferente format() .

Das Abfangen der Ausnahme so weit wie möglich von dem Punkt entfernt, an dem sie ausgelöst wurde, sorgt für einfacheren Code und liefert gleichzeitig mehr Informationen.

0 Stimmen

Das ist viel besser als die vorherige(n) Methode(n), aber immer noch lächerlich umständlich, nur um einen Stacktrace auszugeben. Java braucht weniger Code F

24voto

soumya-kole Punkte 671

In Python 3 (funktioniert in 3.9) können wir eine Funktion definieren, die wir überall dort verwenden können, wo wir die Details ausgeben wollen.

import traceback

def get_traceback(e):
    lines = traceback.format_exception(type(e), e, e.__traceback__)
    return ''.join(lines)

try:
    1/0
except Exception as e:
    print('------Start--------')
    print(get_traceback(e))
    print('------End--------')

try:
    spam(1,2)
except Exception as e:
    print('------Start--------')
    print(get_traceback(e))
    print('------End--------')

Die Ausgabe würde wie folgt aussehen:

bash-3.2$ python3 /Users/soumyabratakole/PycharmProjects/pythonProject/main.py
------Start--------
Traceback (most recent call last):
  File "/Users/soumyabratakole/PycharmProjects/pythonProject/main.py", line 26, in <module>
    1/0
ZeroDivisionError: division by zero

------End--------
------Start--------
Traceback (most recent call last):
  File "/Users/soumyabratakole/PycharmProjects/pythonProject/main.py", line 33, in <module>
    spam(1,2)
NameError: name 'spam' is not defined

------End--------

15voto

nupanick Punkte 541

Wenn Sie bereits ein Error-Objekt haben und das Ganze ausdrucken wollen, müssen Sie diesen etwas umständlichen Aufruf machen:

import traceback
traceback.print_exception(type(err), err, err.__traceback__)

Das ist richtig, print_exception nimmt drei positionale Argumente: Der Typ der Ausnahme, das eigentliche Ausnahmeobjekt und die interne Traceback-Eigenschaft der Ausnahme.

In Python 3.5 oder höher kann die type(err) ist optional... aber es ist ein Positionsargument, so dass Sie immer noch explizit None an seiner Stelle übergeben müssen.

traceback.print_exception(None, err, err.__traceback__)

Ich habe keine Ahnung, warum das alles nicht einfach traceback.print_exception(err) . Warum man einen Fehler zusammen mit einem anderen Traceback als dem, der zu diesem Fehler gehört, ausgeben möchte, ist mir schleierhaft.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X