Was ist der Grund für das Bestehen des Try-außer-else?
Mit einem try
Block können Sie einen erwarteten Fehler behandeln. Der except
Block sollte nur Ausnahmen abfangen, für die Sie bereit sind. Wenn Sie einen unerwarteten Fehler behandeln, kann Ihr Code das Falsche tun und Fehler verbergen.
Eine else
Klausel wird ausgeführt, wenn keine Fehler aufgetreten sind. Wenn Sie diesen Code nicht im try
Block ausführen, vermeiden Sie, dass ein unerwarteter Fehler auftritt. Auch hier kann das Abfangen eines unerwarteten Fehlers Fehler verbergen.
Beispiel
Zum Beispiel:
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
else:
return something
Die Suite "try, without" enthält zwei optionale Klauseln else
und finally
. So ist es eigentlich try-except-else-finally
.
else
wird nur ausgewertet, wenn es keine Ausnahme vom try
Block gibt. Dies ermöglicht es uns, den komplizierteren Code unten zu vereinfachen:
no_error = None
try:
try_this(whatever)
no_error = True
except SomeException as the_exception:
handle(the_exception)
if no_error:
return something
Wenn wir also eine else
mit der Alternative vergleichen (was zu Fehlern führen kann), stellen wir fest, dass dadurch die Codezeilen reduziert werden und wir eine besser lesbare, wartbare und weniger fehlerhafte Codebasis haben können.
finally
finally
wird ausgeführt, egal was passiert, auch wenn eine andere Zeile mit einer return-Anweisung ausgewertet wird.
Mit Pseudocode aufgeschlüsselt
Es kann hilfreich sein, dies in der kleinstmöglichen Form, die alle Funktionen demonstriert, mit Kommentaren aufzuschlüsseln. Angenommen, dieser syntaktisch korrekte (aber nicht ausführbare, wenn die Namen nicht definiert sind) Pseudocode befindet sich in einer Funktion.
Zum Beispiel:
try:
try_this(whatever)
except SomeException as the_exception:
handle_SomeException(the_exception)
# Handle a instance of SomeException or a subclass of it.
except Exception as the_exception:
generic_handle(the_exception)
# Handle any other exception that inherits from Exception
# - doesn't include GeneratorExit, KeyboardInterrupt, SystemExit
# Avoid bare `except:`
else: # there was no exception whatsoever
return something()
# if no exception, the "something()" gets evaluated,
# but the return will not be executed due to the return in the
# finally block below.
finally:
# this block will execute no matter what, even if no exception,
# after "something" is eval'd but before that value is returned
# but even if there is an exception.
# a return here will hijack the return functionality. e.g.:
return True # hijacks the return in the else clause above
Es ist wahr, dass wir den Code stattdessen in den Block des Blocks aufnehmen könnten , wo er ausgeführt würde, wenn es keine Ausnahmen gäbe, aber was ist, wenn dieser Code selbst eine Ausnahme der Art auslöst, die wir abfangen? Wenn Sie es im Block belassen, wird dieser Fehler ausgeblendet.else
try
try
Wir möchten die Codezeilen im try
Block minimieren, um zu vermeiden, dass Ausnahmen abgefangen werden, die wir nicht erwartet haben. Dabei möchten wir, dass unser Code lautstark fehlschlägt, wenn er fehlschlägt. Dies ist eine bewährte Methode .
Nach meinem Verständnis sind Ausnahmen keine Fehler
In Python sind die meisten Ausnahmen Fehler.
Wir können die Ausnahmehierarchie mit pydoc anzeigen. Zum Beispiel in Python 2:
$ python -m pydoc exceptions
oder Python 3:
$ python -m pydoc builtins
Wird uns die Hierarchie geben. Wir können sehen, dass die meisten Arten von Exception
Fehlern sind, obwohl Python einige davon für Dinge wie das Beenden von for
Schleifen ( StopIteration
) verwendet. Dies ist die Hierarchie von Python 3:
BaseException
Exception
ArithmeticError
FloatingPointError
OverflowError
ZeroDivisionError
AssertionError
AttributeError
BufferError
EOFError
ImportError
ModuleNotFoundError
LookupError
IndexError
KeyError
MemoryError
NameError
UnboundLocalError
OSError
BlockingIOError
ChildProcessError
ConnectionError
BrokenPipeError
ConnectionAbortedError
ConnectionRefusedError
ConnectionResetError
FileExistsError
FileNotFoundError
InterruptedError
IsADirectoryError
NotADirectoryError
PermissionError
ProcessLookupError
TimeoutError
ReferenceError
RuntimeError
NotImplementedError
RecursionError
StopAsyncIteration
StopIteration
SyntaxError
IndentationError
TabError
SystemError
TypeError
ValueError
UnicodeError
UnicodeDecodeError
UnicodeEncodeError
UnicodeTranslateError
Warning
BytesWarning
DeprecationWarning
FutureWarning
ImportWarning
PendingDeprecationWarning
ResourceWarning
RuntimeWarning
SyntaxWarning
UnicodeWarning
UserWarning
GeneratorExit
KeyboardInterrupt
SystemExit
Ein Kommentator fragte:
Angenommen, Sie haben eine Methode, die eine externe API pingt, und Sie möchten die Ausnahme in einer Klasse außerhalb des API-Wrappers behandeln. Geben Sie einfach e von der Methode unter der Ausnahme-Klausel zurück, wobei e das Ausnahmeobjekt ist?
Nein, Sie geben die Ausnahme nicht zurück, sondern erhöhen sie nur mit einem Bare raise
, um die Stapelverfolgung beizubehalten .
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
raise
In Python 3 können Sie auch eine neue Ausnahme auslösen und die Rückverfolgung mit Ausnahmeverkettung beibehalten:
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
raise DifferentException from the_exception
Ich gehe hier auf meine Antwort ein .