Wie kann ich eine Ausnahme in Python auslösen, damit sie später über einen except
Block abgefangen werden kann ?
Wie kann ich eine Ausnahme in Python manuell auslösen / auslösen?
Verwenden Sie den spezifischsten Ausnahmekonstruktor, der semantisch zu Ihrem Problem passt .
Seien Sie in Ihrer Nachricht genau, z. B.:
raise ValueError('A very specific bad thing happened.')
Vermeiden Sie es, ein Generikum zu erheben Exception
. Um es abzufangen, müssen Sie alle anderen spezifischeren Ausnahmen abfangen, die es unterordnen.
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
Zum Beispiel:
def demo_bad_catch():
try:
raise ValueError('Represents a hidden bug, do not catch this')
raise Exception('This is the exception you expect to handle')
except Exception as error:
print('Caught this error: ' + repr(error))
>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)
Und spezifischere Fänge werden die allgemeine Ausnahme nicht erfassen:
def demo_no_catch():
try:
raise Exception('general exceptions not caught by specific handling')
except ValueError as e:
print('we will not catch exception: Exception')
>>> demo_no_catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling
raise
Aussageraise ValueError('A very specific bad thing happened')
Dies ermöglicht auch die Übergabe einer beliebigen Anzahl von Argumenten an den Konstruktor:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
Auf diese Argumente wird über das args
Attribut des Exception
Objekts zugegriffen . Zum Beispiel:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
druckt
('message', 'foo', 'bar', 'baz')
In Python 2.5, ein tatsächliches message
wurde Attribut hinzugefügt , um BaseException
für den Einsatz von Benutzern Unterklasse Ausnahmen und Stop ermutigend args
, aber die Einführung message
und die ursprüngliche deprecation von args zurückgezogen worden ist .
except
KlauselWenn Sie sich in einer Ausnahmeklausel befinden, möchten Sie beispielsweise protokollieren, dass ein bestimmter Fehlertyp aufgetreten ist, und ihn dann erneut auslösen. Der beste Weg, dies unter Beibehaltung des Stack-Trace zu tun, ist die Verwendung einer Bare-Raise-Anweisung. Zum Beispiel:
logger = logging.getLogger(__name__)
try:
do_something_in_app_that_breaks_easily()
except AppError as error:
logger.error(error)
raise # just this!
# raise AppError # Don't do this, you'll lose the stack trace!
Sie können den Stacktrace (und den Fehlerwert) mit beibehalten sys.exc_info()
, dies ist jedoch weitaus fehleranfälliger und weist Kompatibilitätsprobleme zwischen Python 2 und 3 auf. Verwenden Sie raise
zum erneuten Erhöhen lieber ein Bare .
Zur Erklärung: sys.exc_info()
Gibt den Typ, den Wert und den Traceback zurück.
type, value, traceback = sys.exc_info()
Dies ist die Syntax in Python 2 - beachten Sie, dass dies nicht mit Python 3 kompatibel ist:
raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
Wenn Sie möchten, können Sie ändern, was mit Ihrer neuen Erhöhung geschieht - z. B. neue Einstellungen args
für die Instanz:
def error():
raise ValueError('oops!')
def catch_error_modify_message():
try:
error()
except ValueError:
error_type, error_instance, traceback = sys.exc_info()
error_instance.args = (error_instance.args[0] + ' <modification>',)
raise error_type, error_instance, traceback
Und wir haben den gesamten Traceback beibehalten, während wir die Argumente geändert haben. Beachten Sie, dass dies keine bewährte Methode ist und die Syntax in Python 3 ungültig ist (was die Beibehaltung der Kompatibilität erheblich erschwert).
>>> catch_error_modify_message()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch_error_modify_message
File "<stdin>", line 2, in error
ValueError: oops! <modification>
In Python 3 :
raise error.with_traceback(sys.exc_info()[2])
Nochmals: Vermeiden Sie die manuelle Bearbeitung von Tracebacks. Es ist weniger effizient und fehleranfälliger. Und wenn Sie Threading verwenden und sys.exc_info
möglicherweise sogar das falsche Traceback erhalten (insbesondere, wenn Sie die Ausnahmebehandlung für den Kontrollfluss verwenden - was ich persönlich eher vermeiden würde).
In Python 3 können Sie Ausnahmen verketten, die Tracebacks beibehalten:
raise RuntimeError('specific message') from error
Sei vorsichtig:
Diese können sich leicht verstecken und sogar in den Produktionscode gelangen. Sie möchten eine Ausnahme auslösen, und wenn Sie dies tun, wird eine Ausnahme ausgelöst, aber nicht die beabsichtigte!
In Python 2, jedoch nicht in Python 3, gilt Folgendes:
raise ValueError, 'message' # Don't do this, it's deprecated!
Nur in viel älteren Versionen von Python (2.4 und niedriger) gültig , sehen Sie möglicherweise immer noch Leute, die Zeichenfolgen erhöhen:
raise 'message' # really really wrong. don't do this.
In allen modernen Versionen wird dadurch tatsächlich a ausgelöst TypeError
, da Sie keinen BaseException
Typ erhöhen . Wenn Sie nicht nach der richtigen Ausnahme suchen und keinen Prüfer haben, der sich des Problems bewusst ist, kann es in die Produktion gehen.
Ich löse Ausnahmen aus, um Verbraucher vor meiner API zu warnen, wenn sie diese falsch verwenden:
def api_func(foo):
'''foo should be either 'baz' or 'bar'. returns something very useful.'''
if foo not in _ALLOWED_ARGS:
raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))
"Ich möchte absichtlich einen Fehler machen, damit er in die Ausnahme geht."
Sie können Ihre eigenen Fehlertypen erstellen. Wenn Sie angeben möchten, dass etwas Bestimmtes mit Ihrer Anwendung nicht stimmt, klassifizieren Sie einfach den entsprechenden Punkt in der Ausnahmehierarchie:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
und Verwendung:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
raise
das, was ich brauchte, um ein benutzerdefiniertes Fehler-Debugging auf mehreren Ebenen der Codeausführung durchführen zu können, ohne den Stack-Trace zu unterbrechen.raise sys.exc_info()[0], (sys.exc_info()[1], my_extra_info), sys.exc_info()[2]
scheint zu tun, was ich will, und ich habe nie Probleme damit gehabt. Aber es fühlt sich hackig an und keine akzeptierte Praxis. Gibt es einen besseren Weg?Exception
Ihrer Elternklasse abgeleitet sind. Sie können etwas Spezifischeres unterordnen und sollten dies tun, wenn es sinnvoll ist.AppError
Ausnahme. Es kann besser sein, einen eingebauten Fehler wieAttributeError
Viel pythonischer geht es nicht:
Siehe die raise - Anweisung docs für Python , wenn Sie weitere Informationen möchten.
quelle
In Python3 gibt es 4 verschiedene Syntaxen für das Auslösen von Ausnahmen:
Wenn Sie
raise exception (args)
eine Ausnahme auslösen,args
wird diese beim Drucken des Ausnahmeobjekts gedruckt - wie im folgenden Beispiel gezeigt.raise
Anweisung ohne Argumente löst die letzte Ausnahme erneut aus. Dies ist nützlich, wenn Sie nach dem Abfangen der Ausnahme einige Aktionen ausführen und sie dann erneut auslösen möchten. Wenn es zuvor keine Ausnahme gab,raise
löst die Anweisung eineTypeError
Ausnahme aus.Diese Anweisung wird verwendet, um eine Ausnahmeverkettung zu erstellen, bei der eine Ausnahme, die als Antwort auf eine andere Ausnahme ausgelöst wird, die Details der ursprünglichen Ausnahme enthalten kann - wie im folgenden Beispiel gezeigt.
Ausgabe:
quelle
exception(args)
alsexception (args)
raise exception(args) from None
zu sagen, dass die derzeit aktive Ausnahme behandelt wurde und nicht mehr von Interesse ist. Andernfalls werdenexcept
Tracebacks für beide Ausnahmen getrennt durch die Meldung "Während der Behandlung der obigen Ausnahme ist eine weitere Ausnahme aufgetreten"Für den allgemeinen Fall, dass Sie als Reaktion auf einige unerwartete Bedingungen eine Ausnahme auslösen müssen und diese niemals abfangen möchten, sondern einfach schnell versagen müssen, damit Sie von dort aus debuggen können, falls dies jemals passieren sollte - die logischste scheint zu sein
AssertionError
::quelle
ValueError
alsAssertionError
weil es kein Problem mit einer Behauptung gibt (weil hier keine gemacht wird) - das Problem liegt bei einem Wert. Wenn SieAssertionError
in diesem Fall wirklich eine wollen , schreiben Sieassert distance > 0, 'Distance must be positive'
. Auf diese Weise sollten Sie jedoch keine Fehler überprüfen, da Zusicherungen deaktiviert werden können (python -O
).-O
.Lesen Sie zuerst die vorhandenen Antworten, dies ist nur ein Nachtrag.
Beachten Sie, dass Sie Ausnahmen mit oder ohne Argumente auslösen können.
Beispiel:
Beendet das Programm, aber Sie möchten vielleicht wissen, was passiert ist. Sie können dies also verwenden.
Dadurch wird "Programm beendet" an stderr ausgegeben, bevor das Programm geschlossen wird.
quelle
raise SystemExit()
die bessere Wahl? Warum funktioniert der erste überhaupt?Eine andere Möglichkeit, Ausnahmen auszulösen, ist
assert
. Sie können assert verwenden, um zu überprüfen, ob eine Bedingung erfüllt ist. Andernfalls wird sie ausgelöstAssertionError
. Weitere Details finden Sie hier .quelle
Nur zur Anmerkung: Es gibt Zeiten, in denen Sie generische Ausnahmen behandeln möchten. Wenn Sie eine Reihe von Dateien verarbeiten und Ihre Fehler protokollieren, möchten Sie möglicherweise alle für eine Datei auftretenden Fehler abfangen, protokollieren und den Rest der Dateien weiter verarbeiten. In diesem Fall a
Blockieren Sie einen guten Weg, um es zu tun. Sie möchten dennoch
raise
bestimmte Ausnahmen festlegen, damit Sie wissen, was sie bedeuten.quelle
Sie sollten dafür die Raise-Anweisung von Python lernen. Es sollte im Try-Block aufbewahrt werden. Beispiel -
quelle