368 Stimmen

Wie kann ich feststellen, welche Art von Ausnahme aufgetreten ist?

some_function() während der Ausführung eine Ausnahme auslöst, springt das Programm zur except :

try:
    some_function()
except:
    print("exception happened!")

Wie erkenne ich die Ursache für das Auftreten der Ausnahme?

588voto

Lauritz V. Thaulow Punkte 45363

Die anderen Antworten weisen alle darauf hin, dass man keine generischen Ausnahmen erwischen sollte, aber niemand scheint Ihnen sagen zu wollen, warum, was wichtig ist, um zu verstehen, wann man die "Regel" brechen kann. Hier ist eine Erklärung. Im Grunde ist es so, dass man sich nicht verstecken muss:

Solange Sie also darauf achten, nichts davon zu tun, ist es in Ordnung, die generische Ausnahme abzufangen. Sie könnten dem Benutzer beispielsweise auf andere Weise Informationen über die Ausnahme zur Verfügung stellen, etwa so:

  • Ausnahmen als Dialoge in einer GUI darstellen
  • Übertragung von Ausnahmen von einem Arbeits-Thread oder -Prozess an den kontrollierenden Thread oder Prozess in einer Multithreading- oder Multiprozessing-Anwendung

Wie kann man also die allgemeine Ausnahme abfangen? Es gibt mehrere Möglichkeiten. Wenn Sie nur das Ausnahmeobjekt haben wollen, gehen Sie wie folgt vor:

try:
    someFunction()
except Exception as ex:
    template = "An exception of type {0} occurred. Arguments:\n{1!r}"
    message = template.format(type(ex).__name__, ex.args)
    print message

Machen Sie sicher message wird dem Nutzer auf eine unübersehbare Weise nahegebracht! Es reicht nicht aus, sie wie oben gezeigt auszudrucken, wenn die Meldung unter vielen anderen Meldungen vergraben ist. Die Aufmerksamkeit des Benutzers nicht zu erregen, ist gleichbedeutend damit, alle Ausnahmen zu schlucken, und wenn es einen Eindruck gibt, den Sie nach dem Lesen der Antworten auf dieser Seite gewonnen haben sollten, dann ist es, dass dies keine gute Sache . Beenden Sie den except-Block mit einem raise Anweisung behebt das Problem, indem sie die abgefangene Ausnahme transparent wieder aufruft.

Der Unterschied zwischen der obigen Vorgehensweise und der alleinigen Verwendung von except: ohne jedes Argument ist zweifach:

  • Eine kahle except: gibt Ihnen das Ausnahmeobjekt nicht zur Prüfung
  • Die Ausnahmen SystemExit , KeyboardInterrupt y GeneratorExit werden von dem obigen Code nicht erfasst, was im Allgemeinen erwünscht ist. Siehe die Ausnahmehierarchie .

Wenn Sie auch die gleiche Stacktrace, die Sie erhalten, wenn Sie nicht fangen die Ausnahme, können Sie, dass wie folgt (immer noch innerhalb der except-Klausel) erhalten:

import traceback
print traceback.format_exc()

Wenn Sie die logging Modul können Sie die Ausnahme (zusammen mit einer Meldung) wie folgt in das Protokoll ausgeben:

import logging
log = logging.getLogger()
log.exception("Message for you, sir!")

Wenn Sie tiefer graben und den Stack untersuchen wollen, sich Variablen usw. ansehen wollen, verwenden Sie die post_mortem Funktion der pdb Modul innerhalb des Except-Blocks:

import pdb
pdb.post_mortem()

Ich habe festgestellt, dass diese letzte Methode bei der Suche nach Fehlern von unschätzbarem Wert ist.

159voto

Alex Punkte 2499

Ermittelt den Namen der Klasse, zu der das Ausnahmeobjekt gehört:

e.__class__.__name__

und mit der Funktion print_exc() wird auch der Stack-Trace ausgegeben, der eine wichtige Information für jede Fehlermeldung ist.

Zum Beispiel so:

from traceback import print_exc

class CustomException(Exception): pass

try:
    raise CustomException("hi")
except Exception as e:
    print ('type is:', e.__class__.__name__)
    print_exc()
    # print("exception happened!")

Sie erhalten dann eine Ausgabe wie diese:

type is: CustomException
Traceback (most recent call last):
  File "exc.py", line 7, in <module>
    raise CustomException("hi")
CustomException: hi

Und nach dem Ausdruck und der Analyse kann der Code entscheiden, die Ausnahme nicht zu behandeln und einfach auszuführen raise :

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except CustomException as e:
    # here do some extra steps in case of CustomException
    print('custom logic doing cleanup and more')
    # then re raise same exception
    raise

Ausgabe:

custom logic doing cleanup and more

Und der Interpreter gibt eine Ausnahme aus:

Traceback (most recent call last):
  File "test.py", line 9, in <module>
    calculate()
  File "test.py", line 6, in calculate
    raise CustomException("hi")
__main__.CustomException: hi

Nach raise Die ursprüngliche Ausnahme breitet sich weiter auf dem Aufrufstapel aus. ( Vorsicht vor möglichen Fallstricken ) Wenn Sie eine neue Ausnahme auslösen, wird ein neuer (kürzerer) Stacktrace erstellt.

from traceback import print_exc

class CustomException(Exception):
    def __init__(self, ok):
        self.ok = ok

def calculate():
    raise CustomException(False)

try:
    calculate()
except CustomException as e:
    if not e.ok:
        # Always use `raise` to rethrow exception
        # following is usually mistake, but here we want to stress this point
        raise CustomException(e.ok)
    print("handling exception")

Ausgabe:

Traceback (most recent call last):
  File "test.py", line 13, in <module>
    raise CustomException(e.message)
__main__.CustomException: hi    

Beachten Sie, dass Traceback nicht die calculate() Funktion ab Zeile 9 die der Ursprung der ursprünglichen Ausnahme ist e .

16voto

hochl Punkte 11724

Normalerweise sollten Sie nicht alle möglichen Ausnahmen mit try: ... except da dies zu weit gefasst ist. Nehmen Sie nur die Fälle auf, die aus irgendeinem Grund zu erwarten sind. Wenn Sie wirklich müssen, zum Beispiel wenn Sie während der Fehlersuche mehr über ein Problem herausfinden wollen, sollten Sie Folgendes tun

try:
    ...
except Exception as ex:
    print ex # do whatever you want for debugging.
    raise    # re-raise exception.

13voto

Piotr Dobrogost Punkte 39650

Die meisten Antworten verweisen auf except (…) as (…): Syntax (zu Recht), aber gleichzeitig will niemand über den Elefanten im Raum sprechen, der der Elefant ist sys.exc_info() Funktion. Von der Dokumentation de sys Modul (Hervorhebung von mir):

Diese Funktion gibt ein Tupel von drei Werten zurück, die Informationen liefern über die Ausnahme, die gerade behandelt wird.
( )
Wenn nirgendwo auf dem Stapel eine Ausnahme behandelt wird, wird ein Tupel zurückgegeben, das drei None-Werte enthält. Andernfalls werden die Werte zurückgegeben (Typ, Wert, Traceback). Ihre Bedeutung ist: t Typ der zu behandelnden Ausnahme (eine Unterklasse von BaseException); value liefert die Instanz der Ausnahme (eine Instanz des Ausnahmetyps); traceback liefert ein Traceback-Objekt (siehe das Referenzhandbuch), das den Aufrufstapel an dem Punkt kapselt, an dem die Ausnahme ursprünglich aufgetreten ist.

Ich denke, die sys.exc_info() könnte als die direkteste Antwort auf die ursprüngliche Frage behandelt werden Woher weiß ich, welche Art von Ausnahme aufgetreten ist?

10voto

Chris Punkte 4518

Diese Antworten sind gut für die Fehlersuche, aber für das programmatische Testen der Ausnahme, isinstance(e, SomeException) kann nützlich sein, da es auf Unterklassen von SomeException Sie können also Funktionen erstellen, die sich auf Hierarchien von Ausnahmen beziehen.

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