Exceptions in Python: Fehler sauber behandeln mit try und except
Programme stürzen ab, sobald etwas Unerwartetes passiert – es sei denn, du fängst Fehler gezielt ab. So nutzt du try, except, else und finally richtig.
Früher oder später passiert es in jedem Programm: Eine Datei fehlt, ein Nutzer gibt Buchstaben statt Zahlen ein oder eine Netzwerkverbindung bricht ab. Ohne Vorkehrung beendet Python dein Programm sofort mit einer Fehlermeldung – einer sogenannten Exception. In diesem Beitrag lernst du, wie du solche Fehler kontrolliert abfängst, sinnvoll darauf reagierst und deinen Code damit robust machst.
Was ist eine Exception?
Eine Exception ist ein Objekt, das Python erzeugt, wenn während der Ausführung etwas schiefgeht. Tritt sie auf, wird der normale Programmfluss unterbrochen. Wenn niemand den Fehler abfängt, bricht das Programm ab und gibt einen sogenannten Traceback aus. Schau dir dieses Beispiel an:
zahl = int("hallo") # ValueError: invalid literal for int()
print("Diese Zeile wird nie erreicht")
Der Aufruf int("hallo") löst einen ValueError aus, weil sich der Text nicht in eine Zahl umwandeln lässt. Das Programm stoppt sofort. Genau hier kommt try/except ins Spiel.
Der try-except-Block
Mit try markierst du den Code, der einen Fehler auslösen könnte. Im except-Block legst du fest, was passieren soll, falls dieser Fehler tatsächlich auftritt:
try:
alter = int(input("Wie alt bist du? "))
print(f"In 10 Jahren bist du {alter + 10}.")
except ValueError:
print("Bitte gib eine gültige Zahl ein.")
Gibt der Nutzer eine Zahl ein, läuft alles wie gewohnt. Gibt er stattdessen "zwanzig" ein, springt Python direkt in den except-Block – das Programm läuft weiter, statt abzustürzen. Du fängst hier gezielt nur ValueError ab, alle anderen Fehlertypen würden weiterhin durchschlagen.
Mehrere Fehlertypen unterscheiden
Oft kann ein Codeblock auf verschiedene Arten scheitern. Du kannst mehrere except-Zweige hintereinander schreiben und so jeweils passend reagieren. Wichtig ist die Reihenfolge: spezifische Fehler zuerst, allgemeinere danach.
def teile(a, b):
try:
return a / b
except ZeroDivisionError:
print("Division durch null ist nicht erlaubt.")
except TypeError:
print("Beide Werte müssen Zahlen sein.")
teile(10, 0) # Division durch null ist nicht erlaubt.
teile(10, "x") # Beide Werte müssen Zahlen sein.
Möchtest du mehrere Fehlertypen gleich behandeln, fasst du sie in einem Tupel zusammen: except (ValueError, TypeError):. Über das Schlüsselwort as bekommst du außerdem Zugriff auf das Fehlerobjekt selbst, etwa um die Meldung auszugeben:
try:
wert = int("abc")
except ValueError as fehler:
print(f"Fehler aufgetreten: {fehler}")
# Ausgabe: Fehler aufgetreten: invalid literal for int() with base 10: 'abc'
else und finally
Der try-Block kennt zwei weitere optionale Teile. Der else-Zweig läuft nur, wenn kein Fehler auftrat – ideal für Code, der vom erfolgreichen Versuch abhängt. Der finally-Zweig läuft immer, egal ob es einen Fehler gab oder nicht. Das ist perfekt zum Aufräumen, etwa um Dateien oder Verbindungen sicher zu schließen.
try:
datei = open("daten.txt")
inhalt = datei.read()
except FileNotFoundError:
print("Die Datei existiert nicht.")
else:
print(f"Datei erfolgreich gelesen: {len(inhalt)} Zeichen")
finally:
print("Aufräumarbeiten abgeschlossen.")
Bei der Dateiverarbeitung übernimmt in der Praxis meist ein with-Block das automatische Schließen. Für andere Ressourcen wie Datenbankverbindungen bleibt finally aber ein wertvolles Werkzeug.
Eigene Fehler auslösen mit raise
Du musst nicht nur auf Fehler reagieren – du kannst sie auch selbst auslösen. Mit raise wirfst du eine Exception, wenn etwas in deiner Logik nicht stimmt. Das macht Funktionen klarer, weil ungültige Eingaben sofort und mit aussagekräftiger Meldung scheitern:
def setze_alter(alter):
if alter < 0:
raise ValueError("Das Alter darf nicht negativ sein.")
return alter
try:
setze_alter(-5)
except ValueError as fehler:
print(fehler) # Das Alter darf nicht negativ sein.
Für komplexere Projekte lohnt es sich, eigene Exception-Klassen zu definieren, indem du von Exception erbst. So lassen sich anwendungsspezifische Fehler gezielt abfangen.
Häufige Stolperfallen
Ein paar Dinge solltest du vermeiden, damit deine Fehlerbehandlung nicht mehr Probleme schafft, als sie löst:
- Kein nacktes
except:– fängt jeden Fehler ab, auch Tippfehler in deinem Code, und verschleiert echte Bugs. Fange immer möglichst konkrete Typen ab. - Fehler nicht still schlucken – ein leerer
except: passversteckt Probleme. Logge oder melde mindestens, was passiert ist. - try-Blöcke klein halten – umschließe nur die Zeile, die wirklich fehlschlagen kann, nicht halbe Funktionen. So weißt du genau, woher ein Fehler stammt.
Fazit
Exceptions sind kein Zeichen für schlechten Code, sondern ein zentrales Werkzeug, um mit dem Unerwarteten umzugehen. Mit try und except fängst du Fehler gezielt ab, mit else und finally strukturierst du den Ablauf sauber, und mit raise machst du deine eigene Logik widerstandsfähig. Fange dabei immer nur die Fehler ab, mit denen du wirklich rechnest – so bleibt dein Programm robust, ohne echte Bugs zu verstecken. Probiere es im nächsten Skript direkt aus: Suche eine Stelle, die abstürzen könnte, und mach sie krisensicher.