Fangen Sie den vollständigen Python-Ausnahme-Traceback ab und drucken Sie ihn aus, ohne das Programm anzuhalten/zu beenden
Lesezeit: 11 Minuten
Chriscauley
Ich möchte Ausnahmen abfangen und protokollieren, ohne das Programm 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 try/exclusive die Ausnahme abfängt, und das tue ich auch nicht Ich möchte, dass es mein Programm beendet.
Keine vollständige Antwort, aber jemand möchte vielleicht wissen, dass Sie auf viele Informationen zugreifen können, die Sie untersuchen err.__traceback__ (zumindest in Python 3.x)
– Vito Gentile
25. Februar 2021 um 12:10 Uhr
Es scheint, dass ich der Einzige auf der Welt bin, der den Stapel drucken 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 herausfinden kann, wie er hierher gekommen ist!)).
– Olivier Pons
2. Juni 2021 um 8:23
Um das wahre Zen von Python zu verstehen, @PavelVlasov, muss man auch wissen, wann das Zen von Python nicht Zen ist. Vor der Aufklärung, den Stack-Traces folgend, nach der Aufklärung, den Stack-Traces folgend. Eines Tages wirst du es verstehen und Frieden finden, Grashüpfer. Kehren Sie nicht zur Korruption von Java zurück, aus der Sie gekommen sind.
Verwenden Sie nicht exc … der Traceback enthält alle Informationen stackoverflow.com/questions/4564559/…
– droid192
8. September 2019 um 18:11 Uhr
print(sys.exc_info()[2]) Erträge <traceback object at 0x0000028A79E6B2C8>.
– Teepeemm
14. Okt. 2020 um 14:23
print(traceback.format_exc()) ist besser als traceback.print_tb(exc.__traceback__). print(sys.exc_info()) gibt das gesamte Tupel zurück und sieht so aus (<class 'UnicodeDecodeError'>, UnicodeDecodeError('utf-8', b'\x81', 0, 1, 'invalid start byte'), <traceback object at 0x7f179d64ae00>) Also tatsächlich traceback.format_exc() ist wirklich überlegen, weil das druckt Traceback (most recent call last): File "<ipython-input-15-9e3d6e01ef04>", line 2, in <module> b"\x81".decode() UnicodeDecodeError: 'utf-8' codec can't decode byte 0x81 in position 0: invalid start byte
– Markieren
7. Mai 2021 um 20:47 Uhr
Entfernen Sie das exc_info() es funktioniert nicht.
– usamec
2. August 2022 um 12:26 Uhr
Sylvain Leroux
Einige andere Antworten haben bereits darauf hingewiesen zurück verfolgen Modul.
Bitte beachten Sie das mit print_excIn einigen Einzelfällen erhalten Sie jedoch nicht das, was Sie erwarten würden. In Python 2.x:
Traceback (most recent call last):
File "e.py", line 7, in <module>
raise TypeError("Again !?!")
TypeError: Again !?!
Wenn Sie wirklich auf das Original zugreifen müssen zurück verfolgen Eine Lösung besteht darin, das zwischenzuspeichern Ausnahmeinformationen wie zurückgegeben von exc_info in einer lokalen Variablen und zeigen Sie es mit an print_exception:
import traceback
import sys
try:
raise TypeError("Oups!")
except Exception, err:
try:
exc_info = sys.exc_info()
# do you usefull stuff here
# (potentially raising an exception)
try:
raise TypeError("Again !?!")
except:
pass
# end of useful stuff
finally:
# Display the *original* exception
traceback.print_exception(*exc_info)
del exc_info
Produzieren:
Traceback (most recent call last):
File "t.py", line 6, in <module>
raise TypeError("Oups!")
TypeError: Oups!
Das Zuweisen des Traceback-Rückgabewerts zu einer lokalen Variablen in einer Funktion, die eine Ausnahme behandelt, führt zu einem Fehler zirkulärer Verweis. Dadurch wird verhindert, dass alles, was von einer lokalen Variablen in derselben Funktion oder vom Traceback referenziert wird, durch Garbage Collection erfasst wird. […] Wenn Sie den Traceback dennoch benötigen, löschen Sie ihn unbedingt nach der Verwendung (Am besten mit einem Versuch machen … schließlich Aussage)
aber aus demselben Dokument:
Ab Python 2.2 werden solche Zyklen automatisch zurückgefordert Wenn die Garbage Collection aktiviert ist und sie nicht mehr erreichbar sind, bleibt es effizienter, die Erstellung von Zyklen zu vermeiden.
Zum anderen, indem wir Ihnen den Zugriff auf das Traceback ermöglichen verknüpft mit Eine Ausnahme liefert Python 3 ein weniger überraschendes Ergebnis:
Es ist nicht erforderlich, manuell eine Ausnahme auszulösen, nur um sie erneut abzufangen.
Das Traceback-Modul macht genau das – es löst eine Ausnahme aus und fängt sie ab.
– pappig
7. November 2015 um 19:08
Die Ausgabe erfolgt übrigens standardmäßig an STDERR. Erscheint nicht in meinen Protokollen, weil es woanders umgeleitet wurde.
– mpen
11. Dezember 2018 um 0:18
@pppery Ich kann es mit Python 3.8 nicht sehen. Und die Sache mit try Und catch ist, dass nicht der vollständige Traceback angezeigt wird, sondern nur von raise Zu except.
– x-yuri
25. Juni 2020 um 19:12 Uhr
Russland muss Putin absetzen
Wie drucke ich den vollständigen Traceback aus, ohne das Programm anzuhalten?
Wenn Sie Ihr Programm bei einem Fehler nicht anhalten möchten, müssen Sie diesen Fehler mit einem Try/Except behandeln:
try:
do_something_that_might_error()
except Exception as error:
handle_the_error(error)
Um den vollständigen Traceback zu extrahieren, verwenden wir die traceback Modul aus der Standardbibliothek:
import traceback
Und um einen einigermaßen komplizierten Stacktrace zu erstellen, um zu zeigen, dass wir den vollständigen Stacktrace erhalten:
def raise_error():
raise RuntimeError('something bad happened!')
def do_something_that_might_error():
raise_error()
Drucken
Zu drucken Den vollständigen Traceback verwenden Sie traceback.print_exc Methode:
try:
do_something_that_might_error()
except Exception as error:
traceback.print_exc()
Was druckt:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
Besser als Drucken, Protokollieren:
Eine bewährte Vorgehensweise besteht jedoch darin, einen Logger für Ihr Modul einzurichten. Es kennt den Namen des Moduls und kann Ebenen ändern (neben anderen Attributen, z. B. Handlern).
In diesem Fall möchten Sie das logger.exception Funktion stattdessen:
try:
do_something_that_might_error()
except Exception as error:
logger.exception(error)
Welche Protokolle:
ERROR:__main__:something bad happened!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
Oder vielleicht möchten Sie einfach nur die Zeichenfolge, in diesem Fall möchten Sie die traceback.format_exc Funktion stattdessen:
try:
do_something_that_might_error()
except Exception as error:
logger.debug(traceback.format_exc())
Welche Protokolle:
DEBUG:__main__:Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
Abschluss
Und für alle drei Optionen sehen wir, dass wir die gleiche Ausgabe erhalten wie bei einem Fehler:
>>> do_something_that_might_error()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
Was zu verwenden ist
Leistungsbedenken spielen hier keine Rolle, da IO normalerweise dominiert. Ich würde es vorziehen, da es genau das tut, was angefordert wird, und zwar auf vorwärtskompatible Weise:
logger.exception(error)
Protokollierungsstufen und -ausgaben können angepasst werden, sodass das Ausschalten einfach ist, ohne den Code zu berühren. Und normalerweise ist es am effizientesten, das zu tun, was direkt benötigt wird.
Antonius
Erstens nicht verwenden printFür die Protokollierung gibt es eine stabile, bewährte und durchdachte Lösung stdlib Modul, um das zu tun: logging. Du auf jeden Fall sollen Verwenden Sie es stattdessen.
Zweitens: Lassen Sie sich nicht dazu verleiten Durcheinander mit unabhängigen Tools, wenn es einen nativen und einfachen Ansatz gibt. Hier ist es:
log = logging.getLogger(__name__)
try:
call_code_that_fails()
except MyError:
log.exception('Any extra info you want to see in your logs')
Das ist es. Sie sind jetzt fertig.
Erklärung für alle, die sich dafür interessieren, wie die Dinge unter der Haube funktionieren
Was log.exception ist eigentlich nur ein Anruf log.error (d. h. Ereignis mit Level protokollieren ERROR) Und Drucken Sie dann den Traceback aus.
Warum ist es besser?
Nun, hier sind einige Überlegungen:
es ist nur Rechts;
es ist unkompliziert;
es ist einfach.
Warum sollte niemand verwenden traceback oder Logger anrufen mit exc_info=True oder sich die Hände schmutzig machen sys.exc_info?
Naja, einfach so! Sie alle dienen unterschiedlichen Zwecken. Zum Beispiel, traceback.print_excDie Ausgabe unterscheidet sich ein wenig von den vom Interpreter selbst erstellten Tracebacks. Wenn Sie es verwenden, verwirren Sie jeden, der Ihre Protokolle liest, und er wird mit dem Kopf darüber stoßen.
Vorbeigehen exc_info=True Anrufe zu protokollieren ist einfach unangemessen. AberDies ist nützlich, wenn Sie behebbare Fehler erkennen und diese protokollieren möchten (z. B. mithilfe von INFO Ebene) auch mit Tracebacks, weil log.exception erzeugt Protokolle nur einer Ebene – ERROR.
Und Sie sollten es auf jeden Fall vermeiden, sich damit anzulegen sys.exc_info so viel wie du kannst. Es ist einfach keine öffentliche Schnittstelle, sondern eine interne – Sie dürfen Verwenden Sie es, wenn Sie genau wissen, was Sie tun. Es ist nicht nur zum Drucken von Ausnahmen gedacht.
Es funktioniert auch nicht so wie es ist. Das ist es nicht. Ich bin jetzt noch nicht fertig: Diese Antwort verschwendet nur Zeit.
– A. Rager
27. April 2019 um 16:07 Uhr
Ich würde auch hinzufügen, dass Sie es einfach tun können logging.exception(). Es ist nicht erforderlich, eine Protokollinstanz zu erstellen, es sei denn, Sie haben besondere Anforderungen.
– Shital Shah
18. Mai 2019 um 6:35 Uhr
Ich finde diese Antwort irgendwie lächerlich. Es ist voll von „Tu das/Tu das nicht, nur weil“, ohne zu erklären, warum. Ihre Punkte in „Warum ist es besser?“ bedeutet praktisch, dass alle dasselbe sagen: „weil es so ist.“ Was ich nicht hilfreich finde. Du hast es zumindest ein wenig erklärt.
– Brechen
18. Dezember 2020 um 1:28
Gute Informationen (ich wusste nichts davon logging.exception), aber etwas herablassend. Ich denke, das liegt eher an der Sprachbarriere als an böswilliger Absicht.
– rjh
5. September 2021 um 14:49 Uhr
Was dieser Typ gesagt hat. In meiner Firma feuern wir jeden, der sich per Printprotokoll anmeldet. /S
– Omni
14. Januar 2022 um 12:33 Uhr
traceback.format_exception(exception_object)
Wenn Sie nur das Ausnahmeobjekt haben, können Sie den Traceback als String von jedem Punkt des Codes in Python 3 abrufen mit:
Siehe auch: Traceback-Informationen aus einem Ausnahmeobjekt extrahieren
Getestet in Python 3.9
Es funktioniert auch nicht so wie es ist. Das ist es nicht. Ich bin jetzt noch nicht fertig: Diese Antwort verschwendet nur Zeit.
– A. Rager
27. April 2019 um 16:07 Uhr
Ich würde auch hinzufügen, dass Sie es einfach tun können logging.exception(). Es ist nicht erforderlich, eine Protokollinstanz zu erstellen, es sei denn, Sie haben besondere Anforderungen.
– Shital Shah
18. Mai 2019 um 6:35 Uhr
Ich finde diese Antwort irgendwie lächerlich. Es ist voll von „Tu das/Tu das nicht, nur weil“, ohne zu erklären, warum. Ihre Punkte in „Warum ist es besser?“ bedeutet praktisch, dass alle dasselbe sagen: „weil es so ist.“ Was ich nicht hilfreich finde. Du hast es zumindest ein wenig erklärt.
– Brechen
18. Dezember 2020 um 1:28
Gute Informationen (ich wusste nichts davon logging.exception), aber etwas herablassend. Ich denke, das liegt eher an der Sprachbarriere als an böswilliger Absicht.
– rjh
5. September 2021 um 14:49 Uhr
Was dieser Typ gesagt hat. In meiner Firma feuern wir jeden, der sich per Printprotokoll anmeldet. /S
– Omni
14. Januar 2022 um 12:33 Uhr
Neuron
Zusätzlich zur Antwort von Aaron Hall, wenn Sie protokollieren, es aber nicht verwenden möchten logging.exception() (da es auf der ERROR-Ebene protokolliert wird), können Sie eine niedrigere Ebene verwenden und bestehen exc_info=True. z.B
Dies ist auch nützlich, wenn es um einen erkannten Protokollierungsfehler geht, z. B. wenn es Ihnen aus irgendeinem Grund nicht gelungen ist, ein tatsächliches Logger-Objekt zu erstellen.
– Mike Nagetier
21. Dezember 2021 um 17:09 Uhr
14534000cookie-checkFangen Sie den vollständigen Python-Ausnahme-Traceback ab und drucken Sie ihn aus, ohne das Programm anzuhalten/zu beendenyes
Keine vollständige Antwort, aber jemand möchte vielleicht wissen, dass Sie auf viele Informationen zugreifen können, die Sie untersuchen
err.__traceback__
(zumindest in Python 3.x)– Vito Gentile
25. Februar 2021 um 12:10 Uhr
Es scheint, dass ich der Einzige auf der Welt bin, der den Stapel drucken 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 herausfinden kann, wie er hierher gekommen ist!)).
– Olivier Pons
2. Juni 2021 um 8:23
Um das wahre Zen von Python zu verstehen, @PavelVlasov, muss man auch wissen, wann das Zen von Python nicht Zen ist. Vor der Aufklärung, den Stack-Traces folgend, nach der Aufklärung, den Stack-Traces folgend. Eines Tages wirst du es verstehen und Frieden finden, Grashüpfer. Kehren Sie nicht zur Korruption von Java zurück, aus der Sie gekommen sind.
– NeilG
28. April um 1:01