In Python können beim Auftreten von Ausnahmen (Exceptions) Fehler an anderer Stelle im Code ausgelöst werden, während die ursprüngliche Ausnahme noch erhalten bleibt. Dies ist besonders nützlich, wenn du eine Ausnahme abfangen möchtest, aber eine neue, spezifischere Ausnahme auslösen musst.
In diesem Tutorial lernst du implizites und explizites Exception Chaining in Python kennen und wie man es benutzt.
Exception Chaining in Python ist ein nützliches Werkzeug, um Fehler in einer klaren und nachvollziehbaren Weise zu verketten.
Die Wahl zwischen implizitem und explizitem Chaining hängt davon ab, ob du die ursprüngliche Ausnahme explizit behandeln möchtest oder nicht. In jedem Fall bietet Python mit Exception Chaining eine Möglichkeit, Fehlersituationen transparent zu machen und deren Ursache einfach nachzuvollziehen.
Das implizite Exception Chaining tritt auf, wenn innerhalb eines except
-Blocks eine neue Ausnahme ausgelöst wird, ohne explizit die ursprüngliche Ausnahme zu referenzieren. Python verknüpft die ursprüngliche Ausnahme automatisch mit der neuen Ausnahme über das Attribut __context__
.
try:
1 / 0 # Löst ZeroDivisionError aus
except ZeroDivisionError:
raise ValueError("Ein Fehler trat auf.") # Löst ValueError aus
In diesem Beispiel tritt zuerst eine ZeroDivisionError
-Ausnahme auf. Innerhalb des except
-Blocks wird jedoch eine neue Ausnahme, ein ValueError
, ausgelöst. Python verknüpft den ursprünglichen Fehler mit dem neuen, und die ursprüngliche Ausnahme ist unter dem Attribut __context__
verfügbar.
Wenn du das Programm ausführst, wird der Fehlerverlauf angezeigt, einschließlich des ursprünglichen Fehlers:
Traceback (most recent call last):
File "example.py", line 2, in <module>
1 / 0
ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "example.py", line 4, in <module>
raise ValueError("Ein Fehler trat auf.")
ValueError: Ein Fehler trat auf.
try:
numbers = [1, 2, 3]
print(numbers[5]) # Löst IndexError aus
except IndexError:
raise KeyError("Falscher Schlüssel.")
Auch hier tritt zuerst ein IndexError
auf, weil auf ein nicht existierendes Element der Liste zugegriffen wird. Danach wird ein KeyError
ausgelöst, der mit dem ursprünglichen Fehler verkettet wird:
Traceback (most recent call last):
File "example.py", line 3, in <module>
print(numbers[5])
IndexError: list index out of range
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "example.py", line 5, in <module>
raise KeyError("Falscher Schlüssel.")
KeyError: 'Falscher Schlüssel.'
Beim expliziten Exception Chaining kannst du die ursprüngliche Ausnahme explizit referenzieren, wenn du eine neue Ausnahme auslöst. Das geschieht mit dem Schlüsselwort from
. Hierdurch wird die neue Ausnahme mit der alten verknüpft, und du kannst explizit festlegen, welche Ausnahme der Verursacher war.
try:
open("nicht_existierende_datei.txt") # Löst FileNotFoundError aus
except FileNotFoundError as e:
raise RuntimeError("Fehler beim Öffnen der Datei.") from e
In diesem Beispiel tritt ein FileNotFoundError
auf, weil die Datei nicht existiert. Wir fangen diese Ausnahme ab und lösen explizit eine neue RuntimeError
-Ausnahme aus, die mit der ursprünglichen Ausnahme FileNotFoundError
verknüpft ist:
Traceback (most recent call last):
File "example.py", line 2, in <module>
open("nicht_existierende_datei.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'nicht_existierende_datei.txt'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "example.py", line 4, in <module>
raise RuntimeError("Fehler beim Öffnen der Datei.") from e
RuntimeError: Fehler beim Öffnen der Datei.
Hier wird explizit der FileNotFoundError
als Ursache für den RuntimeError
angegeben.
Manchmal kann eine Ausnahme mehrfach verkettet werden, z. B. wenn mehrere Ausnahmen in verschiedenen Ebenen des Programms auftreten. Das folgende Beispiel zeigt, wie man eine Kette von Ausnahmen erstellt:
try:
raise ValueError("Ursprünglicher Fehler.")
except ValueError as e:
try:
raise TypeError("Ein weiterer Fehler.") from e
except TypeError as te:
raise RuntimeError("Endgültiger Fehler.") from te
Hier tritt eine Kette von Ausnahmen auf: Zuerst ValueError
, dann TypeError
, und schließlich RuntimeError
, alle miteinander verkettet.
Traceback (most recent call last):
File "example.py", line 4, in <module>
raise ValueError("Ursprünglicher Fehler.")
ValueError: Ursprünglicher Fehler.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "example.py", line 7, in <module>
raise TypeError("Ein weiterer Fehler.") from e
TypeError: Ein weiterer Fehler.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "example.py", line 9, in <module>
raise RuntimeError("Endgültiger Fehler.") from te
RuntimeError: Endgültiger Fehler.
In Python gibt es zwei Attribute, die sich mit Exception Chaining beschäftigen: __context__
und __cause__
. Beide spielen eine Rolle beim Verketten von Ausnahmen, aber sie werden in unterschiedlichen Situationen verwendet.
Hier sind die Unterschiede:
__context__
:
except
-Blocks auftritt (implizites Exception Chaining).__context__
automatisch aus, wenn du eine neue Ausnahme auslöst, während du eine andere Ausnahme abfängst.__context__
zeigt auf die ursprüngliche Ausnahme, die nicht explizit angegeben wurde.__cause__
:
raise ... from ...
auftritt.raise NewException from OldException
schreibst, wird die alte Ausnahme (OldException
) in das Attribut __cause__
der neuen Ausnahme (NewException
) gespeichert.__cause__
hebt die Verkettung explizit hervor und gibt dir mehr Kontrolle über die Ausnahmeursache.__context__
Hier wird gezeigt, wie __context__
in einem Fall von implizitem Exception Chaining verwendet wird:
try:
try:
1 / 0 # Löst ZeroDivisionError aus
except ZeroDivisionError:
raise ValueError("Fehler in der Berechnung") # Neue Ausnahme wird ausgelöst
except ValueError as e:
print("ValueError aufgetreten:", e)
if e.__context__:
print("Ursprüngliche Ausnahme (__context__):", e.__context__)
ZeroDivisionError
wird im inneren try
-Block ausgelöst.except
-Block wird eine neue Ausnahme ValueError
ausgelöst.ZeroDivisionError
in __context__
.ValueError aufgetreten: Fehler in der Berechnung
Ursprüngliche Ausnahme (__context__): division by zero
__cause__
Im folgenden Beispiel verwenden wir explizites Exception Chaining mit raise ... from ...
:
try:
try:
open("nicht_existierende_datei.txt") # Löst FileNotFoundError aus
except FileNotFoundError as e:
raise RuntimeError("Fehler beim Öffnen der Datei") from e
except RuntimeError as e:
print("RuntimeError aufgetreten:", e)
if e.__cause__:
print("Ursprüngliche Ausnahme (__cause__):", e.__cause__)
FileNotFoundError
wird ausgelöst, da die Datei nicht existiert.RuntimeError
wird explizit mit from
verknüpft.FileNotFoundError
wird in __cause__
gespeichert.RuntimeError aufgetreten: Fehler beim Öffnen der Datei
Ursprüngliche Ausnahme (__cause__): [Errno 2] No such file or directory: 'nicht_existierende_datei.txt'
Finden Sie interessante und zum Thema passende Kurse
Beginnen Sie Ihre Programmierkarriere mit unserem Python-Einführungskurs. Erlernen Sie grundlegende Konzepte wie Variablen, Schleifen und Datenstrukturen und bauen Sie eine solide Basis in Python auf. Durch praxisnahe Projekte und kompetente Anleitung entwickeln Sie wertvolle Programmierfähigkeiten.
5 Tage Vollzeit auch als Feierabendkurs Online
Nächster Termin: 20. Januar 2025
Preis pro Person: 1600,00 EUR
Rabattaktion: 3 für den Preis von 2!
Diese Schulung „Python für Fortgeschrittene“ vertieft fortgeschrittene Programmiertechniken in Python, wie objektorientierte Programmierung, funktionale Programmierung und Persistenz. Die Teilnehmer lernen, wie sie komplexe Designs und Muster in Python umsetzen, effiziente Datenverarbeitung durchführen und wissenschaftliche Python-Bibliotheken nutzen können. Die Schulung bietet zudem praxisnahe Einblicke in Datenbanken, Metaklassen, Caching und maschinelles Lernen mit scikit-learn.
5 Tage Vollzeit Online
Nächster Termin: 13. Januar 2025
Preis pro Person: 1900,00 EUR
Rabattaktion: 3 für den Preis von 2!
In diesem dreitägigen Data Science Seminar mit Python lernen Teilnehmer, wie sie Daten effizient mit Python-Datenstrukturen verarbeiten, analysieren und visualisieren. Die Schulung umfasst die Arbeit mit NumPy und Pandas sowie die Erstellung von aussagekräftigen Diagrammen mit Matplotlib.
3 Tage Vollzeit Online
Nächster Termin: noch kein Datum bekannt
Preis pro Person: 1200,00 EUR
Rabattaktion: 3 für den Preis von 2!