Mein Hintergrund ist C # und ich habe erst kürzlich angefangen, in Python zu programmieren. Wenn eine Ausnahme ausgelöst wird, möchte ich sie normalerweise in eine andere Ausnahme einschließen, die weitere Informationen hinzufügt und gleichzeitig die vollständige Stapelverfolgung anzeigt. In C # ist das ganz einfach, aber wie mache ich das in Python?
Z.B. in C # würde ich so etwas machen:
try
{
ProcessFile(filePath);
}
catch (Exception ex)
{
throw new ApplicationException("Failed to process file " + filePath, ex);
}
In Python kann ich etwas Ähnliches tun:
try:
ProcessFile(filePath)
except Exception as e:
raise Exception('Failed to process file ' + filePath, e)
... aber das verliert den Traceback der inneren Ausnahme!
Bearbeiten: Ich möchte beide Ausnahmemeldungen und beide Stapelspuren sehen und die beiden korrelieren. Das heißt, ich möchte in der Ausgabe sehen, dass hier die Ausnahme X und dort die Ausnahme Y aufgetreten ist - genau wie in C #. Ist das in Python 2.6 möglich? Das Beste, was ich bisher tun kann (basierend auf Glenn Maynards Antwort), ist:
try:
ProcessFile(filePath)
except Exception as e:
raise Exception('Failed to process file' + filePath, e), None, sys.exc_info()[2]
Dies umfasst sowohl die Nachrichten als auch die Tracebacks, zeigt jedoch nicht an, welche Ausnahme wo im Traceback aufgetreten ist.
Antworten:
Python 2
Es ist einfach; Übergeben Sie den Traceback als drittes Argument.
Tun Sie dies immer, wenn Sie eine Ausnahme abfangen und eine andere erneut auslösen.
quelle
raise MyException(str(e)), ...
usw.raise E() from tb
und.with_traceback(...)
raise
ist der Wert, der an die Ausnahme übergeben werden soll (falls das erste Argument eine Ausnahmeklasse und keine Instanz ist). Wenn Sie also Ausnahmen austauschen möchten, anstatt dies zu tunraise MyException(str(e)), None, sys.exc_info()[2]
, ist es besser, Folgendes zu verwenden :raise MyException, e.args, sys.exc_info()[2]
.from future.utils import raise_
undraise_(ValueError, None, sys.exc_info()[2])
.Python 3
In Python 3 können Sie Folgendes tun:
Dies wird ungefähr so etwas hervorbringen:
quelle
raise ... from ...
ist in der Tat der richtige Weg, dies in Python 3 zu tun. Dies erfordert mehr Upvotes.Nakedible
Ich denke, das liegt daran, dass die meisten Leute Python 3 leider immer noch nicht verwenden.future
Paket verwenden, um dies zu erreichen: python-future.org/compatible_idioms.html#raising-exceptions ZBfrom future.utils import raise_
undraise_(ValueError, None, sys.exc_info()[2])
.Python 3 hat die Klausel
raise
...from
, um Ausnahmen zu verketten. Glenns Antwort ist großartig für Python 2.7, verwendet jedoch nur den Traceback der ursprünglichen Ausnahme und wirft die Fehlermeldung und andere Details weg. Hier sind einige Beispiele in Python 2.7, die Kontextinformationen aus dem aktuellen Bereich in die Fehlermeldung der ursprünglichen Ausnahme einfügen, andere Details jedoch beibehalten.Bekannter Ausnahmetyp
Diese
raise
Anweisung verwendet den Ausnahmetyp als ersten Ausdruck, die Argumente des Ausnahmeklassenkonstruktors in einem Tupel als zweiten Ausdruck und den Traceback als dritten Ausdruck. Wenn Sie früher als Python 2.2 ausgeführt werden, lesen Sie die Warnungen untersys.exc_info()
.Beliebiger Ausnahmetyp
Hier ist ein weiteres Beispiel, das allgemeiner ist, wenn Sie nicht wissen, welche Ausnahmen Ihr Code möglicherweise abfangen muss. Der Nachteil ist, dass es den Ausnahmetyp verliert und nur einen RuntimeError auslöst. Sie müssen das
traceback
Modul importieren .Ändern Sie die Nachricht
Hier ist eine weitere Option, wenn Sie mit dem Ausnahmetyp Kontext hinzufügen können. Sie können die Nachricht der Ausnahme ändern und dann erneut erhöhen.
Dadurch wird der folgende Stack-Trace generiert:
Sie können sehen, dass die Zeile angezeigt wird,
check_output()
in der aufgerufen wurde, aber die Ausnahmemeldung enthält jetzt die Befehlszeile.quelle
ex.strerror
? Ich kann keinen relevanten Treffer dafür in den Python-Dokumenten finden. Sollte es nicht seinstr(ex)
?IOError
wird abgeleitet vonEnvironmentError
@hheimbuerger, das die Attributeerrorno
und bereitstelltstrerror
.Error
, z. B. ValueError,RuntimeError
durch Fangen in einen einwickelnException
? Wenn ich Ihre Antwort für diesen Fall wiedergebe, geht die Stapelverfolgung verloren.In Python 3.x :
oder einfach
Dies wird sich verbreiten,
MyException
aber beide Ausnahmen drucken, wenn es nicht behandelt wird.In Python 2.x :
Sie können das Drucken beider Ausnahmen verhindern, indem Sie das
__context__
Attribut beenden. Hier schreibe ich einen Kontextmanager, der dies verwendet, um Ihre Ausnahme im laufenden Betrieb abzufangen und zu ändern: ( Weitere Informationen zur Funktionsweise finden Sie unter http://docs.python.org/3.1/library/stdtypes.html. )quelle
e.__traceback__
Attribut!Ich glaube nicht, dass Sie dies in Python 2.x tun können, aber etwas Ähnliches wie diese Funktionalität ist Teil von Python 3. Aus PEP 3134 :
Vergleich mit C #:
Beachten Sie auch, dass Java, Ruby und Perl 5 diese Art von Dingen ebenfalls nicht unterstützen. Nochmals zitieren:
quelle
Für maximale Kompatibilität zwischen Python 2 und 3 können Sie
raise_from
in dersix
Bibliothek verwenden. https://six.readthedocs.io/#six.raise_from . Hier ist Ihr Beispiel (aus Gründen der Übersichtlichkeit leicht modifiziert):quelle
Sie können meine CausedException-Klasse verwenden, um Ausnahmen in Python 2.x zu verketten (und sogar in Python 3 kann dies nützlich sein, wenn Sie mehr als eine abgefangene Ausnahme als Ursache für eine neu ausgelöste Ausnahme angeben möchten). Vielleicht kann es dir helfen.
quelle
Vielleicht könnten Sie die relevanten Informationen greifen und weitergeben? Ich denke so etwas wie:
quelle
Angenommen:
raise ... from
Lösung)Sie können eine einfache Lösung aus den Dokumenten https://docs.python.org/3/tutorial/errors.html#raising-exceptions verwenden :
Die Ausgabe:
Es sieht so aus, als wäre das Schlüsselstück das vereinfachte "Raise" -Schlüsselwort, das für sich allein steht. Dadurch wird die Ausnahme im Ausnahmeblock erneut ausgelöst.
quelle