Richtig auf Fehler reagieren Ausnahmebehandlung in Python

Von Thomas Joos

Die Fehler- und Ausnahmebehandlung spielt auch in einem Python-Programm eine wichtige Rolle. Denn übergeordnete Funktionen auch dann weiterarbeiten, wenn in untergeordneten Funktionen Fehler auftreten.

Ausnahmebehandlungen stellen auch in Python sicher, dass ein Programm trotz fehlerhafter Funktionen weiterläuft.
Ausnahmebehandlungen stellen auch in Python sicher, dass ein Programm trotz fehlerhafter Funktionen weiterläuft.
(Bild: JohnsonMartin)

Rufen Funktionen Unterfunktionen auf, kann es immer wieder passieren, dass Fehler in den Unterfunktionen auftreten. Hier ist es wichtig, dass zum einen die übergeordneten Funktionen weiter funktionieren. Zum anderen muss auch sichergestellt sein, dass die Unterfunktion den Fehler nach oben kommuniziert, sodass die übergeordnete Funktion entsprechend reagieren kann.

Übergeordnete Funktionen müssen also immer in der Lage sein, Fehler von Funktionen, die sie wiederum aufrufen, zu verwalten und zu behandeln. Kommt nur eine Funktion zum Einsatz und meldet diese einen Fehler, ist dieser durch seinen Rückgabewert leicht zu behandeln. Wenn aber viele Funktionen im Einsatz sind und auch eine komplexe Verschachtelung vorliegt, spielt es durchaus eine Rolle, wie die übergeordneten Funktionen auf Fehler von anderen Funktionen reagieren.

Exceptions in Python

Python verfügt über interne Mechanismen, mit denen Ausnahmen (Exceptions) im Programmcode erkannt werden können. Übergeordnete Funktionen erhalten eine entsprechende Rückmeldung und können auf die Exception reagieren.

Die Funktion kann die Exception entgegennehmen, auf den Fehler so reagieren, wie es der Programmierer vorgesehen hat, und mit seiner Arbeit fortfahren. Liegt eine verschachtelte Struktur vor, ist es möglich, den Fehler zusätzlich an weitere, übergeordnete Funktionen weiterzuleiten. Auch diese Funktion kann wieder auf den Fehler reagieren und die weitere Übermittlung einstellen.

Untergeordnete Funktionen, die Fehler von weiteren untergeordneten Funktionen erhalten, können diese auch ohne eine eigene Fehlerbehandlung weiterleiten. Die übergeordnete Funktion ist dann in der Lage zu entscheiden, ob sie eine Fehlerbehandlung durchführen soll oder ob der Fehler weiter nach oben geleitet wird.

Python kennt mehrere Exceptions, darunter SyntaxError, NameError und TypeError. Diese Exceptions können auch im Quellcode genutzt werden:

>>> NameError
<class 'NameError'>
>>> SyntaxError
<class 'SyntaxError'>
>>> TypeError
<class 'TypeError'>

Alle Exceptions werden in der Basisklasse „BaseExceptions“ zusammengefasst. Das Attribut „args“ von BaseException gibt die Parameter aus, die bei der Ausnahme übergeben wurde. Das hilft bei der Fehlersuche, da dadurch auch klar ist, welche Parameter unter Umständen schuld am Fehler sind:

a=BaseException(1,2,3,4,5,6,7)
a.args

Der Befehl gibt anschließend (1,2,3,4,5,6,7) aus.

Beispiele für den Ablauf von Exceptions

Einfach ausgedrückt bedeutet das: Wenn im Programm eine Funktion A die Funktion B aufruft und diese die Funktion C startet, dann kann es durchaus passieren, dass in Funktion C ein Fehler auftritt. Behandelt der Programmcode in Funktion C den Fehler nicht, leitet der Interpreter die Ausnahme an Funktion B weiter und anschließend an Funktion A.

Tritt ein Fehler in Python auf, hält der Interpreter das Programm an und übergibt den Fehler an den Prozess oder die Funktion. Wenn Programmcode vorliegt, der die Behandlung des Fehlers durchführt, läuft das Programm weiter. Ist keine Behandlung des auftretenden Fehlers vorgesehen, stürzt das Python-Programm ab. Dies wäre der Fall, wenn in keiner der drei Funktionen eine Fehlerbehandlung für die Funktion C definiert wurde.

Python kann Fehlermeldungen mit try/except-Anweisungen behandeln. Dazu wird der Code in den try-Bereich integriert, und der Code zur Ausnahmenbehandlung in der except-Klausel:

try:
   Anweisung 1
   Anweisung 2
   Anweisung 3
except:
   Anweisung 1
   Anweisung 2
   Anweisung 3

Für eine bessere Übersicht sollten try/except-Blöcke sowie die darunter angeordneten Codeblöcke eingerückt werden. Wenn im Try-Codeblock eine Ausnahme auftritt, fährt der Code mit den Befehlen aus dem Except-Codeblock fort. Grundsätzlich sollten über den Except-Block auch die ExceptionTypes angegeben werden, die durch diesen Block behandelt werden sollen, zum Beispiel:

except (FileNotFoundError, TypeError):

Wenn im Code kein Exception Type angegeben ist, behandelt except alle Ausnahmen, die auftreten. Das ist selten sinnvoll, da im Codeblock nicht alle Fehler abfangbar sind. Es ist sinnvoller, für die einzelnen Ausnahmetypen auch eigene Codeblöcke zu definieren.

Natürlich ist es auch notwendig, für alle Exception Types einen eigenen Except-Block zu erstellen. Am Ende der Blöcke kann mit einem else- und finally-Zweig definiert werden, was passieren soll, wenn die Ausnahme durch keinen Except-Block abgefangen werden kann.

Jetzt Newsletter abonnieren

Täglich die wichtigsten Infos zu Softwareentwicklung und DevOps

Mit Klick auf „Newsletter abonnieren“ erkläre ich mich mit der Verarbeitung und Nutzung meiner Daten gemäß Einwilligungserklärung (bitte aufklappen für Details) einverstanden und akzeptiere die Nutzungsbedingungen. Weitere Informationen finde ich in unserer Datenschutzerklärung.

Aufklappen für Details zu Ihrer Einwilligung

Der Finally-Zweig am Ende wird in jedem Fall ausgeführt, wenn ein Try-Block mit oder ohne Exceptions beendet worden ist. In vielen Fällen wird finally genutzt, um Ressourcen freizugeben, die durch den Codeblock reserviert wurden, zum Beispiel:

try:
   f = open("test.txt",encoding = 'utf-8')
finally:
   f.close()

Eigene Ausnahmen erzeugen

Es ist auch möglich, eigene Ausnahmen auf Basis bestehender Exception Types zu erzeugen. Dazu wird „raise“ verwendet:

raise SyntaxError("Hallo Welt")

Der Befehl gibt in diesem Fall folgende Informationen aus:

Traceback (most recent call last):   File "<pyshell#11>", line 1, in <module>
      raise SyntaxError("Hallo Welt")
   File "<string>", line None
SyntaxError: Hallo Welt

Ein weiteres Beispiel ist:

raise KeyboardInterrupt

Parallel dazu besteht die Möglichkeit, Exceptions zu verwenden, für die es keinen eingebauten ExceptionType gibt. Auch eigene Typen sind in Python definierbar. Dazu wird eine eigene Klasse erstellt und der ExceptionType definiert, zum Beispiel:

class CustomError(Exception):
   pass

Auch diese Ausnahme lässt sich mit raise manuell erzeugen:

raise CustomError

(ID:47393119)