Menu

Python-Ausnahmen: try, except, else, finally und raise

Wie du Fehler in Python behandelst — try/except/finally, gezielt Ausnahmen fangen, eigene werfen und wann du einen Fehler hochschlagen lässt.

Fehler sind einfach Werte mit schlechter Laune

Geht in Python etwas schief — durch Null teilen, eine fehlende Datei lesen, eine schlechte Zahl parsen —, erzeugt die Laufzeit ein Ausnahme-Objekt und wickelt den Aufrufstapel ab, bis etwas sie fängt. Fängt nichts sie, wird dein Programm beendet und ein Traceback gedruckt.

Ausnahmen sind nicht per se schlecht. Sie sind, wie Python signalisiert: „ich kann mit dieser Operation nicht weitermachen; das ist der Grund“. Dein Job ist, Fall für Fall zu entscheiden, von welchen du weißt, wie du dich erholst, und welche du eskalieren lassen solltest.

Die Grundform

main.py
Output
Click Run to see the output here.
  • try: öffnet den Block mit riskantem Code.
  • except ValueError: fängt genau diese Ausnahme, wenn sie im try geworfen wird.
  • Fällt keine Ausnahme, wird das except komplett übersprungen.

Führ das Snippet mit 42 aus — funktioniert. Mit hello — läuft der Handler.

Gezielt Ausnahmen fangen

Python hat eine Hierarchie von Ausnahmetypen. Ein paar, denen du oft begegnest:

  • ValueError — ein Wert war irgendwie falsch (int("abc"), Argumente außerhalb des Bereichs).
  • TypeError — der falsche Typ wurde genutzt ("hi" + 3).
  • KeyError — ein Dict-Schlüssel wurde nicht gefunden.
  • IndexError — ein Sequenz-Index lag außerhalb des Bereichs.
  • FileNotFoundError — eine Datei existiert nicht.
  • ZeroDivisionError — durch Null zu teilen versucht.
  • AttributeError — ein Objekt hat das angefragte Attribut nicht.

Fang die konkrete, die du behandeln kannst:

main.py
Output
Click Run to see the output here.

Du kannst mehrere Ausnahmen in einer Klausel als Tupel fangen:

main.py
Output
Click Run to see the output here.

Beachte das as e. Das bindet das Ausnahme-Objekt an e, damit du Nachricht oder Attribute inspizieren kannst.

Vermeide alles zu fangen

Ein nacktes except: fängt wörtlich alles, auch KeyboardInterrupt (dein Strg-C) und System-Exits. Nutz es nicht.

except Exception: ist etwas besser, aber immer noch gefährlich — es schluckt Bugs, die du nicht erwartet hast, und verbirgt die echte Ursache:

# Don't do this without a really good reason.
try:
    do_something()
except Exception:
    pass

Der richtige Zug ist fast immer, die konkrete Ausnahme zu fangen, von der du weißt, wie du dich erholst. Erreicht eine unerwartete Ausnahme den oberen Rand deines Programms, sagt dir der Traceback genau, was schief ging — das ist ein Feature, kein Bug.

else und finally

Die try-Anweisung hat zwei weitere optionale Klauseln:

  • else läuft, wenn der try-Block ohne Ausnahme beendet wurde.
  • finally läuft immer — mit oder ohne Ausnahme.
main.py
Output
Click Run to see the output here.

else ist der sauberste Ort für „nur bei Erfolg“-Code — ein try-Block sollte nicht mehr enthalten als den tatsächlich fehleranfälligen Teil. finally ist für Aufräumarbeiten, die auch bei Fehler laufen müssen: Ressource schließen, Lock freigeben, Zustand wiederherstellen.

Selbst Ausnahmen werfen

Mit raise signalisierst du einen Fehler in eigenem Code:

main.py
Output
Click Run to see the output here.

Wähl einen Ausnahmetyp, der zum Problem passt. Greif zuerst zu den Eingebauten — ValueError, TypeError, FileNotFoundError —, bevor du eine eigene Klasse definierst.

Eine eigene Ausnahme definieren

Wenn die Eingebauten die Bedeutung nicht treffen, definier eine eigene Ausnahme:

main.py
Output
Click Run to see the output here.

Erbe von Exception (oder einer spezifischeren Eingebauten) und gib der Klasse einen Docstring. Mehr brauchst du meist nicht. Eigene Ausnahmen erlauben Aufruferinnen, nur den für ihre Domäne relevanten Fehler zu fangen.

raise ... from ...: verkettete Ausnahmen

Wenn eine Ausnahme eine andere auslöst, erhalte die Kette:

main.py
Output
Click Run to see the output here.

Das from e hängt den Originalfehler an. Wird der Traceback gedruckt, zeigt Python beide — den aufgetauchten ConfigError und den FileNotFoundError, der ihn verursacht hat. Diese Spur ist beim Debuggen unbezahlbar.

Context Manager: der sauberere Weg zum Aufräumen

finally ist okay, aber für Ressourcen wie Dateien ist ein Context Manager (was with nutzt) fast immer besser:

# finally version
f = open("data.txt")
try:
    data = f.read()
finally:
    f.close()

# with version
with open("data.txt") as f:
    data = f.read()

Beide sind sicher. Die with-Form ist kürzer und greift automatisch. Greif zu finally nur, wenn du etwas tust, was die Standardbibliothek nicht ohnehin in einen Context Manager wickelt.

Wann du nicht fangen solltest

Eine Ausnahme zu fangen ist eine Entscheidung — du sagst „ich kann das behandeln“. Kannst du es nicht, lass die Ausnahme hochgehen. Code wie dieser ist fast immer ein Fehler:

try:
    do_work()
except Exception:
    pass  # silently ignore everything

Fehler zu unterdrücken macht Bugs unsichtbar. Besser laut abstürzen als in einem inkonsistenten Zustand weiterhumpeln.

Zusammenfassung

  • try/except erlaubt dir, Fehler zu behandeln, von denen du dich erholen kannst.
  • Fang konkrete Ausnahmen, nicht Exception pauschal.
  • raise signalisiert Fehler in eigenem Code.
  • with-Blöcke ersetzen die meisten finally-Aufräumarbeiten.
  • Im Zweifel: lass die Ausnahme durch.

Als Nächstes: eine Tour durch die konkreten Fehler, die Python am häufigsten wirft — KeyError, ValueError, ModuleNotFoundError und ein paar mehr — plus die Debugging-Gewohnheiten, die sie schnell beheben.

Häufig gestellte Fragen

Wie behandle ich Fehler in Python?

Wickle riskanten Code in einen try-Block und fang die konkrete Ausnahme in einem except-Block: try: risky() except ValueError: .... Das optionale else läuft, wenn keine Ausnahme fiel; finally läuft in beiden Fällen, für Aufräumarbeiten.

Soll ich zur Sicherheit Exception fangen?

Nein. Ein nacktes except: oder except Exception: versteckt Bugs, mit denen du nicht gerechnet hast. Fang die konkrete Ausnahme, von der du weißt, wie du dich erholen kannst, und lass alles andere hochgehen, damit du das echte Problem siehst.

Was ist der Unterschied zwischen raise und raise from?

raise NewError(...) wirft eine neue Ausnahme. raise NewError(...) from original hängt die Originalausnahme als Ursache mit an, was Python im Traceback zeigt. Nimm from, wenn ein tieferliegender Fehler einen höheren ausgelöst hat, den du sichtbar machen willst.

Lerne mit Coddy zu programmieren

LOS GEHT'S