Exceptions¶
In diesem Abschnitt geht es um Ausnahmen (englisch exceptions), d.h. um Sprachfunktionen, die speziell ungewöhnliche Umstände während der Ausführung eines Programms behandeln. Die häufigste Ausnahme ist die Behandlung von Fehlern, aber sie können auch für viele andere Zwecke effektiv eingesetzt werden. Python bietet einen umfassenden Satz von Ausnahmen, und ihr könnt neue Ausnahmen für eure eigenen Zwecke definieren.
Eine Exception ist ein Objekt, das automatisch von Python-Funktionen mit einer raise-Anweisung erzeugt wird, z.B. mit:
11 if line == "":
12 raise EmptyFileError(f"{file} is empty")
Die raise-Anweisung veranlasst die Ausführung des
Python-Programms auf eine andere Art und Weise, als üblicherweise vorgesehen:
Die aktuelle Aufrufkette wird nach einem Handler durchsucht, der die erzeugte
Ausnahme behandeln kann. Wenn ein solcher Handler gefunden wird, wird er
aufgerufen und kann auf das Ausnahmeobjekt zugreifen, um weitere Informationen
zu erhalten, wie in unserem EmptyFileError
-Beispiel:
1class EmptyFileError(Exception):
2 pass
Dies definiert euren eigenen Ausnahmetyp, der vom Basistyp Exception
erbt.
Eine Übersicht über die Klassenhierarchie eingebauter Exceptions erhaltet ihr
unter Exception hierarchy in der
Python-Dokumentation. Jeder Ausnahmetyp ist eine Python-Klasse, die von ihrem
übergeordneten Exception-Typ erbt. So ist z.B. ein
ZeroDivisionError
durch Vererbung auch ein ArithmeticError
, eine
Exception
und auch eine BaseException
. Diese Hierarchie ist gewollt: Die
meisten Ausnahmen erben von Exception
, und es wird dringend empfohlen, dass
alle benutzerdefinierten Ausnahmen auch die Unterklasse von Exception
und
nicht von BaseException
bilden:
Es ist möglich, verschiedene Arten von Ausnahmen zu erzeugen, um die tatsächliche Ursache des gemeldeten Fehlers oder außergewöhnlichen Umstandes zu reflektieren.
8 try:
9 f = open(file, "r")
10 line = f.readline()
11 if line == "":
12 raise EmptyFileError(f"{file} is empty")
13 except OSError as error:
14 print(f"Cannot open file {file}: {error.strerror}")
15 except EmptyFileError as error:
16 print(error)
Wenn während der Ausführung von open()
im try
-Block ein OSError
oder ein EmptyFileError
auftritt, wird der jeweils zugehörige
except
-Block ausgeführt.
Wird kein geeigneter Exception-Handler gefunden, bricht das Programm mit einer
Fehlermeldung ab. Daher ergänzen wir unsere try
-except
-Anweisungen um
else
und finally
:
17 else:
18 print(f"{file}: {f.readline()}")
19 finally:
20 print("File", file, "processed")
21 f.close()
Nun können wir noch eine Liste unterschiedlicher Datei-Arten definieren, sodass unser vollständiger Code folgendermaßen aussieht:
1class EmptyFileError(Exception):
2 pass
3
4
5filenames = ["myFile1.py", "nonExistent.py", "emptyFile.py", "myFile2.py"]
6
7for file in filenames:
8 try:
9 f = open(file, "r")
10 line = f.readline()
11 if line == "":
12 raise EmptyFileError(f"{file} is empty")
13 except OSError as error:
14 print(f"Cannot open file {file}: {error.strerror}")
15 except EmptyFileError as error:
16 print(error)
17 else:
18 print(f"{file}: {f.readline()}")
19 finally:
20 print("File", file, "processed")
21 f.close()
- Zeile 7
Wenn während der Ausführung der Anweisungen im
try
-Block einOSError
oderEmptyFileError
auftritt, wird der zugehörigeexcept
-Block ausgeführt.- Zeile 9
Hier könnte ein
OSError
ausgelöst werden.- Zeile 12
Hier löst ihr den
EmptyFileError
aus.- Zeile 17
Die
else
-Klausel ist optional; sie wird ausgeführt, wenn imtry
-Block keine Ausnahme auftritt.- Zeile 19
Die
finally
-Klausel ist ebenfalls optional und wird am Ende des Blocks ausgeführt, unabhängig davon, ob eine Ausnahme ausgelöst wurde oder nicht.
Bemerkung
Die Art und Weise, wie Python Fehlersituationen im Allgemeinen behandelt, unterscheidet sich von manch anderen Sprachen, z.B. Java. Diese Sprachen prüfen mögliche Fehler so weit wie möglich, bevor sie auftreten, da die Behandlung von Exceptions nach ihrem Auftreten kostspielig ist. Dies wird manchmal als LBYL-Ansatz bezeichnet.
Bei Python hingegen verlässt man sich eher auf Exceptions, um Fehler zu behandeln, nachdem sie aufgetreten sind. Obwohl dieses Vertrauen riskant erscheinen mag, ist der Code weniger schwerfällig und leichter zu lesen, wenn Exceptions richtig eingesetzt werden, und Fehler werden nur dann behandelt, wenn sie auftreten. Diese pythonische Herangehensweise zur Behandlung von Fehlern wird oft als EAFP beschrieben.
Checks¶
Schreibt Code, der zwei Zahlen erhält und die erste Zahl durch die zweite dividiert. Prüft, ob der
ZeroDivisionError
auftritt, wenn die zweite Zahl0
ist, und fangt diese ab.Wenn
MyError
vonException
erbt, was ist dann der Unterschied zwischenexcept Exception as e
undexcept MyError as e
?Schreibt ein einfaches Programm, das eine Zahl erhält und dann die Anweisung
assert()
verwendet, um eineException
auszulösen, wenn die Zahl0
ist.Schreibt eine benutzerdefinierte Ausnahme
Outliers
, die eineException
auslöst, wenn die Variablex
größer oder kleiner als3
ist?Handelt es sich bei der Überprüfung, ob ein Objekt eine Liste ist (Check: list) um eine Programmierung im Stil von LBYL oder EAFP?