Python Try...Except
Python try, except, else und finally mit klaren Beispielen. Behandle ZeroDivisionError, ValueError, FileNotFoundError und mehr.
Wenn Python zur Laufzeit auf einen Fehler stößt, löst es eine Ausnahme (Exception) aus — ein Objekt, das beschreibt, was schiefgelaufen ist. Ohne Behandlung beendet eine Ausnahme das Programm sofort. Die try...except-Anweisung ermöglicht es, solche Ausnahmen abzufangen, angemessen darauf zu reagieren und das Programm am Laufen zu halten.
Dieses Kapitel behandelt:
- Den
try/except-Block — eine bestimmte Ausnahme abfangen - Ausnahmedetails mit
aserfassen - Mehrere
except-Klauseln und das gleichzeitige Abfangen mehrerer Ausnahmen - Den
else-Block — Code, der nur ausgeführt wird, wenn keine Ausnahme auftritt - Den
finally-Block — Bereinigungscode, der immer ausgeführt wird - Häufige eingebaute Ausnahmen und wann sie auftreten
- Ausnahmen erneut auslösen
- Best Practices und häufige Fehler
Der grundlegende try...except-Block
Umschließe den Code, der möglicherweise fehlschlägt, mit einem try-Block. Wenn Python eine Ausnahme auslöst, springt die Ausführung zum passenden except-Block, anstatt abzustürzen.
Ausgabe:
Error: division by zeroPython versucht die Division, löst ZeroDivisionError aus, und der except-Block behandelt dies. Die as e-Klausel bindet das Ausnahmeobjekt an e, sodass du die Nachricht untersuchen oder protokollieren kannst.
Wenn der try-Block erfolgreich ist, wird der except-Block vollständig übersprungen.
Eine bestimmte Ausnahme abfangen
Benenne immer den Ausnahmetyp, den du erwartest. Das Abfangen eines benannten Typs macht deine Absicht klar und verhindert, dass unbeabsichtigt unzusammenhängende Fehler verborgen werden.
try:
number = int("abc")
except ValueError as e:
print(f"Could not convert: {e}")Ausgabe:
Could not convert: invalid literal for int() with base 10: 'abc'int("abc") löst ValueError aus, weil "abc" keine gültige ganze Zahl ist. Das Angeben von ValueError in der except-Klausel bedeutet, dass jede andere unerwartete Ausnahme weiterhin propagiert wird und als Fehler sichtbar bleibt, anstatt still verschluckt zu werden.
Mehrere except-Klauseln
Ein einzelner try-Block kann mehrere except-Klauseln haben — Python prüft sie von oben nach unten und führt die erste Übereinstimmung aus.
def safe_index(items, index):
try:
return items[index]
except IndexError:
print("Index out of range.")
except TypeError:
print("Index must be an integer.")
safe_index([1, 2, 3], 10) # IndexError
safe_index([1, 2, 3], "a") # TypeErrorAusgabe:
Index out of range.
Index must be an integer.Die Reihenfolge ist wichtig: Platziere spezifischere Ausnahmetypen vor allgemeineren, damit der spezifische Handler zuerst ausgeführt wird.
Mehrere Ausnahmen in einer Klausel abfangen
Wenn zwei oder mehr Ausnahmen die gleiche Reaktion erfordern, gruppiere sie in einem Tupel:
try:
value = int("not-a-number")
except (ValueError, TypeError) as e:
print(f"Input error: {e}")Ausgabe:
Input error: invalid literal for int() with base 10: 'not-a-number'Der else-Block
Der else-Block wird nur ausgeführt, wenn der try-Block ohne das Auslösen einer Ausnahme abgeschlossen wird. Verwende ihn für Code, der bei Erfolg ausgeführt werden soll, aber selbst keinen Fehlerschutz benötigt:
try:
result = 10 / 2
except ZeroDivisionError:
print("Cannot divide by zero.")
else:
print(f"Division succeeded. Result: {result}")Ausgabe:
Division succeeded. Result: 5.0Die Erfolgslogik im else-Block zu halten (statt am Ende des try) verhindert das unbeabsichtigte Abfangen von Ausnahmen, die der Erfolgspfad-Code selbst auslösen könnte.
Der finally-Block
Der finally-Block wird unabhängig davon ausgeführt, was passiert — ob der try-Block erfolgreich ist, eine Ausnahme abgefangen wird oder eine Ausnahme unbehandelt propagiert. Verwende ihn für die Bereinigung: Dateien schließen, Sperren freigeben oder die Verbindung zu einer Datenbank trennen.
try:
result = 10 / 0
except ZeroDivisionError:
print("Error caught.")
finally:
print("This always runs — cleanup goes here.")Ausgabe:
Error caught.
This always runs — cleanup goes here.Auch wenn du den except-Block auskommentierst, wird finally noch ausgeführt, bevor Python die Ausnahme weitergibt.
Vollständige Struktur auf einen Blick
try:
# code that may raise an exception
except SomeException as e:
# handle the exception
except (AnotherError, YetAnother):
# handle either of these
else:
# runs only when try succeeded
finally:
# always runsHäufige eingebaute Ausnahmen
| Ausnahme | Wann sie auftritt |
|---|---|
ZeroDivisionError | Division oder Modulo durch null |
ValueError | Richtiger Typ, falscher Wert (z. B. int("abc")) |
TypeError | Operation auf falschen Typ angewendet |
IndexError | Sequenzindex außerhalb des Bereichs |
KeyError | Dictionary-Schlüssel nicht gefunden |
FileNotFoundError | Datei oder Verzeichnis existiert nicht |
AttributeError | Objekt hat kein solches Attribut |
ImportError | Modul kann nicht importiert werden |
NameError | Variablenname ist nicht definiert |
Alle diese erben von der Basisklasse Exception. Du kannst Exception abfangen, um alle davon in einer Klausel zu behandeln, aber bevorzuge nach Möglichkeit spezifische Typen.
Eine fehlende Datei behandeln
try:
with open("data.txt", "r") as file:
content = file.read()
except FileNotFoundError:
print("Error: File not found.")Ausgabe (wenn data.txt nicht existiert):
Error: File not found.Eine Ausnahme erneut auslösen
Manchmal möchtest du eine Ausnahme protokollieren oder eine teilweise Bereinigung durchführen, sie aber dennoch zum Aufrufer propagieren lassen. Verwende ein bloßes raise innerhalb eines except-Blocks:
def process():
try:
result = 10 / 0
except ZeroDivisionError:
print("Logging error...")
raise # re-raises the original ZeroDivisionError
try:
process()
except ZeroDivisionError as e:
print(f"Outer handler caught: {e}")Ausgabe:
Logging error...
Outer handler caught: division by zeroDas bloße raise bewahrt den ursprünglichen Traceback, sodass das Debuggen nicht schwieriger wird als ohne den Handler.
Die Basisklasse Exception abfangen
Du kannst Exception als Auffangbecken für jeden nicht-systembeendenden Fehler verwenden:
try:
result = 10 / 0
except Exception as e:
print(f"An error occurred: {type(e).__name__}: {e}")Ausgabe:
An error occurred: ZeroDivisionError: division by zerotype(e).__name__ liefert den spezifischen Klassennamen, auch wenn du über die Basisklasse abfängst. Das ist nützlich in Top-Level-Handlern, wo du jeden unerwarteten Fehler protokollieren möchtest.
Bare except — und warum man es vermeiden sollte
Ein bare except (ohne Ausnahmetyp) fängt buchstäblich alles ab, einschließlich KeyboardInterrupt (Strg+C) und SystemExit, was es schwer macht, dein Programm zu unterbrechen:
# Avoid this pattern
try:
result = 10 / 0
except:
print("Some error occurred")Bevorzuge except Exception, wenn du ein breites Netz benötigst, da es KeyboardInterrupt und SystemExit weiterhin normal propagieren lässt.
Best Practices
- Sei spezifisch. Fange den engsten Ausnahmetyp ab, der sinnvoll ist.
- Unterdrücke keine Ausnahmen. Protokolliere mindestens den Fehler; lasse einen
except-Block niemals leer. - Verwende
elsefür Erfolgspfad-Code. Dadurch bleibt dertry-Block so klein wie möglich. - Verwende
finallyfür die Bereinigung. Oder, noch besser, verwende einewith-Anweisung — siehe Python with Statement. - Vermeide bare
except. Verwendeexcept Exception, wenn du ein breites Netz benötigst. - Löse bei Bedarf erneut aus. Wenn du den Fehler nicht vollständig behandeln kannst, lass ihn mit
raisepropagieren.
Informationen zum absichtlichen Auslösen von Ausnahmen und zum Erstellen eigener Ausnahmeklassen findest du unter Python raise and Custom Exceptions.