Python Language
Ausnahmen
Suche…
Einführung
Fehler, die während der Ausführung erkannt werden, werden als Ausnahmen bezeichnet und sind nicht unbedingt tödlich. Die meisten Ausnahmen werden nicht von Programmen behandelt. Es ist möglich, Programme zu schreiben, die ausgewählte Ausnahmen behandeln. Es gibt bestimmte Funktionen in Python, um Ausnahmen und Ausnahmelogik zu behandeln. Außerdem haben Ausnahmen eine reichhaltige BaseException
, die alle vom BaseException
Typ erben.
Syntax
- Ausnahme auslösen
- # erhöhen eine Ausnahme, die bereits ausgelöst wurde
- Ausnahme von Ursache auslösen # Python 3 - Ausnahmeursache festlegen
- Ausnahme von None auslösen # Python 3 - unterdrückt den gesamten Ausnahmekontext
- Versuchen:
- außer [Ausnahmetypen] [ als Bezeichner ] :
- sonst:
- endlich:
Ausnahmen aufwerfen
Wenn Ihr Code auf eine Bedingung stößt, mit der er nicht umgehen kann, beispielsweise ein falscher Parameter, sollte die entsprechende Ausnahme ausgelöst werden.
def even_the_odds(odds):
if odds % 2 != 1:
raise ValueError("Did not get an odd number")
return odds + 1
Ausnahmen fangen
Verwenden Sie try...except:
um Ausnahmen abzufangen. Sie sollten so genau wie möglich eine Ausnahme angeben:
try:
x = 5 / 0
except ZeroDivisionError as e:
# `e` is the exception object
print("Got a divide by zero! The exception was:", e)
# handle exceptional case
x = 0
finally:
print "The END"
# it runs no matter what execute.
Die angegebene Ausnahmeklasse - in diesem Fall ZeroDivisionError
- ZeroDivisionError
alle Ausnahmen, die dieser Klasse oder einer Unterklasse dieser Ausnahmebedingung angehören.
ZeroDivisionError
ist beispielsweise eine Unterklasse von ArithmeticError
:
>>> ZeroDivisionError.__bases__
(<class 'ArithmeticError'>,)
Das Folgende wird also immer noch den ZeroDivisionError
fangen:
try:
5 / 0
except ArithmeticError:
print("Got arithmetic error")
Ausführen von Bereinigungscode mit
Manchmal möchten Sie möglicherweise, dass unabhängig von der aufgetretenen Ausnahme etwas geschieht, beispielsweise wenn Sie einige Ressourcen bereinigen müssen.
Der finally
Block einer try
Klausel wird unabhängig davon ausgeführt, ob Ausnahmen ausgelöst wurden.
resource = allocate_some_expensive_resource()
try:
do_stuff(resource)
except SomeException as e:
log_error(e)
raise # re-raise the error
finally:
free_expensive_resource(resource)
Dieses Muster wird mit Kontextmanagern (mit der Anweisung with
) oft besser behandelt.
Ausnahmen erneut erhöhen
Manchmal möchten Sie eine Ausnahme erfassen, um sie zu prüfen, z. B. zu Protokollierungszwecken. Nach der Inspektion möchten Sie, dass die Ausnahme wie zuvor weitergegeben wird.
Verwenden Sie in diesem Fall einfach die raise
Anweisung ohne Parameter.
try:
5 / 0
except ZeroDivisionError:
print("Got an error")
raise
Beachten Sie jedoch, dass jemand weiter oben im Aufrufer-Stack die Ausnahme noch fangen und irgendwie damit umgehen kann. Die fertige Ausgabe kann in diesem Fall ein Ärgernis sein, da dies auf jeden Fall passieren wird (gefangen oder nicht gefangen). Daher empfiehlt es sich, eine andere Ausnahme auszulösen, die Ihren Kommentar zur Situation sowie die ursprüngliche Ausnahme enthält:
try:
5 / 0
except ZeroDivisionError as e:
raise ZeroDivisionError("Got an error", e)
Dies hat jedoch den Nachteil, dass die Ausnahmespur auf genau diese raise
reduziert wird raise
während die raise
ohne Argument die ursprüngliche Ausnahmespur beibehält.
In Python 3 können Sie den ursprünglichen Stapel beibehalten, indem Sie die raise
- from
- Syntax verwenden:
raise ZeroDivisionError("Got an error") from e
Kettenausnahmen mit Raise from
Bei der Behandlung einer Ausnahme können Sie eine weitere Ausnahme auslösen. Wenn Sie IOError
beim Lesen aus einer Datei einen IOError
, möchten Sie möglicherweise einen anwendungsspezifischen Fehler IOError
, der stattdessen den Benutzern Ihrer Bibliothek angezeigt wird.
Sie können Ausnahmen verketten, um zu zeigen, wie die Behandlung von Ausnahmen abläuft:
>>> try:
5 / 0
except ZeroDivisionError as e:
raise ValueError("Division failed") from e
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ValueError: Division failed
Ausnahmehierarchie
Die Ausnahmebehandlung erfolgt basierend auf einer Ausnahmehierarchie, die durch die Vererbungsstruktur der Ausnahmeklassen bestimmt wird.
Beispielsweise sind IOError
und OSError
beide Unterklassen von EnvironmentError
. Code, der einen IOError
, fängt keinen OSError
. Code, der einen EnvironmentError
IOError
, fängt jedoch sowohl IOError
als auch OSError
s ab.
Die Hierarchie der integrierten Ausnahmen:
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StandardError
| +-- BufferError
| +-- ArithmeticError
| | +-- FloatingPointError
| | +-- OverflowError
| | +-- ZeroDivisionError
| +-- AssertionError
| +-- AttributeError
| +-- EnvironmentError
| | +-- IOError
| | +-- OSError
| | +-- WindowsError (Windows)
| | +-- VMSError (VMS)
| +-- EOFError
| +-- ImportError
| +-- LookupError
| | +-- IndexError
| | +-- KeyError
| +-- MemoryError
| +-- NameError
| | +-- UnboundLocalError
| +-- ReferenceError
| +-- RuntimeError
| | +-- NotImplementedError
| +-- SyntaxError
| | +-- IndentationError
| | +-- TabError
| +-- SystemError
| +-- TypeError
| +-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
+-- 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
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning
Ausnahmen sind auch Objekte
Ausnahmen sind nur reguläre Python-Objekte, die von der integrierten BaseException
erben. Ein Python-Skript kann die Anweisung raise
verwenden, raise
Ausführung zu unterbrechen, sodass Python an diesem Punkt einen Stack-Trace des Aufrufstapels und eine Darstellung der Ausnahmeinstanz ausgibt. Zum Beispiel:
>>> def failing_function():
... raise ValueError('Example error!')
>>> failing_function()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in failing_function
ValueError: Example error!
was besagt, dass ein ValueError
mit der Meldung 'Example error!'
wurde durch unsere failing_function()
, die im Interpreter ausgeführt wurde.
Anrufcode kann beliebige Ausnahmen aller Art behandeln, die ein Anruf auslösen kann:
>>> try:
... failing_function()
... except ValueError:
... print('Handled the error')
Handled the error
Sie können halten , die Ausnahme - Objekte erhalten , indem sie in der Zuordnung except...
Teil des Ausnahmebehandlung Code:
>>> try:
... failing_function()
... except ValueError as e:
... print('Caught exception', repr(e))
Caught exception ValueError('Example error!',)
Eine vollständige Liste der integrierten Python-Ausnahmen mit ihren Beschreibungen finden Sie in der Python-Dokumentation: https://docs.python.org/3.5/library/exceptions.html . Und hier ist die vollständige Liste hierarchisch angeordnet: Ausnahmehierarchie .
Benutzerdefinierte Ausnahmetypen erstellen
Erstellen Sie eine Klasse, die von Exception
erbt:
class FooException(Exception):
pass
try:
raise FooException("insert description here")
except FooException:
print("A FooException was raised.")
oder ein anderer Ausnahmetyp:
class NegativeError(ValueError):
pass
def foo(x):
# function that only accepts positive values of x
if x < 0:
raise NegativeError("Cannot process negative numbers")
... # rest of function body
try:
result = foo(int(input("Enter a positive integer: "))) # raw_input in Python 2.x
except NegativeError:
print("You entered a negative number!")
else:
print("The result was " + str(result))
Fangen Sie nicht alles!
Während es oft versucht ist, jede Exception
zu fangen:
try:
very_difficult_function()
except Exception:
# log / try to reconnect / exit gratiously
finally:
print "The END"
# it runs no matter what execute.
Oder sogar alles (dazu gehören BaseException
und alle BaseException
einschließlich Exception
):
try:
even_more_difficult_function()
except:
pass # do whatever needed
In den meisten Fällen ist es eine schlechte Praxis. Es könnte mehr als beabsichtigt sein, z. B. SystemExit
, KeyboardInterrupt
und MemoryError
Jeder sollte im Allgemeinen anders behandelt werden als MemoryError
System- oder Logikfehler. Dies bedeutet auch, dass es kein klares Verständnis dafür gibt, was der interne Code falsch machen kann und wie er sich von diesem Zustand richtig erholen kann. Wenn Sie jeden Fehler feststellen, wissen Sie nicht, welcher Fehler aufgetreten ist oder wie er zu beheben ist.
Dies wird häufiger als "Bug Masking" bezeichnet und sollte vermieden werden. Lassen Sie Ihr Programm abstürzen, anstatt im Hintergrund zu versagen oder gar zu verschlimmern, und zwar auf einer tieferen Ausführungsebene. (Stellen Sie sich vor, es ist ein Transaktionssystem)
Normalerweise werden diese Konstrukte auf der äußersten Ebene des Programms verwendet und protokollieren die Details des Fehlers, sodass der Fehler behoben werden kann oder der Fehler genauer behandelt werden kann.
Mehrere Ausnahmen abfangen
Es gibt mehrere Möglichkeiten, mehrere Ausnahmen abzufangen .
Die erste besteht darin, ein Tupel der Ausnahmetypen zu erstellen, die auf dieselbe Weise abgefangen und behandelt werden sollen. In diesem Beispiel ignoriert der Code die Ausnahmen KeyError
und AttributeError
.
try:
d = {}
a = d[1]
b = d.non_existing_field
except (KeyError, AttributeError) as e:
print("A KeyError or an AttributeError exception has been caught.")
Wenn Sie unterschiedliche Ausnahmen auf unterschiedliche Weise behandeln möchten, können Sie für jeden Typ einen eigenen Ausnahmeblock bereitstellen. In diesem Beispiel fangen wir immer noch KeyError
und AttributeError
, behandeln die Ausnahmen jedoch auf unterschiedliche Weise.
try:
d = {}
a = d[1]
b = d.non_existing_field
except KeyError as e:
print("A KeyError has occurred. Exception message:", e)
except AttributeError as e:
print("An AttributeError has occurred. Exception message:", e)
Praktische Beispiele für die Behandlung von Ausnahmen
Benutzereingabe
Stellen Sie sich vor, Sie möchten, dass ein Benutzer über die Eingabe eine Nummer input
. Sie möchten sicherstellen, dass die Eingabe eine Zahl ist. Sie können try
/ mit except
davon verwenden:
while True:
try:
nb = int(input('Enter a number: '))
break
except ValueError:
print('This is not a number, try again.')
Hinweis: Python 2.x verwendet stattdessen raw_input
. die Funktion input
existiert in Python 2.x hat aber eine andere Semantik. Im obigen Beispiel würde die input
auch Ausdrücke wie 2 + 2
akzeptieren, die eine Zahl ergeben.
Wenn die Eingabe nicht in eine Ganzzahl konvertiert werden konnte, wird ein ValueError
. Sie können es mit except
fangen. Wenn keine Ausnahme ausgelöst wird break
springt break
aus der Schleife. Nach der Schleife enthält nb
eine ganze Zahl.
Wörterbücher
Stellen Sie sich über eine Liste von aufeinanderfolgenden ganzen Zahlen iterieren, wie range(n)
, und Sie haben eine Liste der Wörterbücher d
, die Informationen über die Dinge enthält zu tun , wenn Sie einige bestimmte ganze Zahlen auftreten, sagen die überspringen d[i]
Nächsten.
d = [{7: 3}, {25: 9}, {38: 5}]
for i in range(len(d)):
do_stuff(i)
try:
dic = d[i]
i += dic[i]
except KeyError:
i += 1
Ein KeyError
wird KeyError
, wenn Sie versuchen, einen Wert aus einem Wörterbuch für einen nicht vorhandenen Schlüssel KeyError
.
Sonst
Code in einem else-Block wird nur ausgeführt, wenn vom Code im try
Block keine Ausnahmen ausgelöst wurden. Dies ist nützlich, wenn Sie Code haben, den Sie nicht ausführen möchten, wenn eine Ausnahme ausgelöst wird. Sie möchten jedoch nicht, dass durch diesen Code ausgelöste Ausnahmen abgefangen werden.
Zum Beispiel:
try:
data = {1: 'one', 2: 'two'}
print(data[1])
except KeyError as e:
print('key not found')
else:
raise ValueError()
# Output: one
# Output: ValueError
Beachten Sie, dass diese Art von else:
nicht mit einer if
-Klausel zu einem elif
. Wenn Sie Folgendes haben, if
es unter dem else:
eingerückt bleiben muss:
try:
...
except ...:
...
else:
if ...:
...
elif ...:
...
else:
...