Python-Entwickler moegen den Satz "it is easier to ask forgiveness than permission". In Python heisst dieser Stil meistens EAFP: Erst die Aktion ausfuehren, dann den Fehler behandeln, falls er wirklich passiert.
Statt jede Zeile mit defensiven Checks zu umstellen, bleibt die eigentliche Business-Logik sichtbar und der Fallback landet im except.
def safe_divide(numerator: float, denominator: float) -> float | None:
try:
return numerator / denominator
except ZeroDivisionError:
print("Division by zero is not allowed.")
Die wichtige Aktion, die Division, steht sofort sichtbar im Code. Der Leser muss nicht erst durch eine Liste von Vorbedingungen laufen, um die Absicht der Funktion zu verstehen.
Der Mythos vom teuren try-except
Entwickler aus C++ oder Java nehmen manchmal an, dass ein try Block Python automatisch langsamer macht. Auf dem normalen Pfad arbeitet modernes Python anders.
Python kompiliert Source Code zu Bytecode und speichert Exception-Metadaten fuer den geschuetzten Bereich. Solange kein Fehler auftritt, kann der Interpreter den Hauptpfad weiter ausfuehren, ohne staendig fuer den Handler zu bezahlen.
Kosten entstehen, wenn eine Exception wirklich geworfen wird. Dann muss Python den Handler finden, den Stack anpassen, in den except Block springen und den Fehlerkontext aufbauen.
Die praktische Regel ist deshalb einfach: Ein try Block ist guenstig, wenn der Fehler selten ist. Wiederholt Exceptions in einer heissen Schleife zu werfen, kann aber teuer werden.
Ein kleines Bytecode-Experiment
Mit dis kannst du die Struktur ansehen:
import dis
code = """
try:
value = int("not-a-number")
except ValueError:
value = 0
"""
dis.dis(code)
Beim Disassemblieren sieht man Bytecode fuer den geschuetzten Block und Informationen zur Exception-Behandlung, die Python sagen, wohin bei einem ValueError gesprungen werden soll.
Keine Exception bedeutet: Der normale Pfad bleibt direkt. Eine Exception bedeutet: Python wechselt in den Recovery-Pfad, den du geschrieben hast.
Wann ein if-Check gewinnt
EAFP ist am staerksten, wenn Fehler ungewoehnlich sind. Wenn der "Fehler" in der Haelfte der Faelle passiert, ist er nicht mehr exceptional, sondern nur noch Overhead.
Ein File-Processing-Job ist ein gutes Beispiel. Wenn du Millionen Pfade pruefst und viele Dateien fehlen, kann ein expliziter Check klarer und schneller sein:
from pathlib import Path
def read_if_exists(path: str) -> str | None:
p = Path(path)
if not p.is_file():
return None
return p.read_text()
In diesem Fall gehoert eine fehlende Datei zum normalen Workload. Keine Flut von FileNotFoundError Exceptions zu erzeugen, haelt die Schleife ruhiger.
Was intern passiert
Vereinfacht laeuft es so:
- Python kompiliert Source Code zu Bytecode und merkt sich, welcher Handler fuer welchen Bytecode-Bereich zustaendig ist.
- Der Interpreter fuehrt den normalen Bytecode-Pfad aus.
- Wenn ein Fehler erscheint, sucht Python die aktuelle Bytecode-Position in den Exception-Daten.
- Python entfernt nicht mehr relevante Stack-Zustaende und springt zum passenden Handler.
- Wenn kein Handler gefunden wird, wandert die Exception nach oben, bis sie gefangen wird oder das Programm mit Traceback endet.
Darum ist Exception Handling angenehm fuer seltene Fehler und laut fuer haeufige Faelle.
Praxisbeispiel: Dictionaries
Dictionary-Lookups sind ein klassischer EAFP-Fall, wenn Misses selten sind:
def price_for(item: str, catalog: dict[str, float]) -> float | None:
try:
return catalog[item]
except KeyError:
print(f"Item {item!r} is not in the catalog.")
In einem normalen Shop-Katalog sollten die meisten Lookups erfolgreich sein. Ein fehlendes Produkt ist wirklich exceptional, also haelt try-except den Happy Path kompakt.
Praxisbeispiel: Network Requests
Auch bei Network Code haelt try-except die Absicht lesbar:
import requests
def fetch_json(url: str) -> dict | None:
try:
response = requests.get(url, timeout=3)
response.raise_for_status()
return response.json()
except (requests.RequestException, ValueError):
print("Unable to fetch or parse data.")
Das Internet ist unzuverlaessig, aber Erfolg ist trotzdem der Pfad, den Leser zuerst sehen sollen. Die Recovery-Logik bleibt an einer Stelle gebuendelt.
Takeaways
Nutze try-except, wenn der Fehler selten ist und die direkte Aktion die Funktion klar beschreibt.
Nutze einen if Check, wenn die Bedingung haeufig, erwartet oder vor der Arbeit billig zu testen ist.
Es gibt keinen universellen Gewinner. Gute Python-Fehlerbehandlung bedeutet auch 2026, die Code-Form an die Wahrscheinlichkeit des Fehlers und die Kosten der Recovery anzupassen.


