DEV Community

Cover image for Python-Fehlerbehandlung 2026: Try-Except oder If-Checks?
Aleksei Aleinikov
Aleksei Aleinikov

Posted on • Originally published at alekseialeinikov.com

Python-Fehlerbehandlung 2026: Try-Except oder If-Checks?

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.

Das ist keine defensive Programmierung. Das ist sauber kontrolliertes Runtime-Chaos.

def safe_divide(numerator: float, denominator: float) -> float | None:
    try:
        return numerator / denominator
    except ZeroDivisionError:
        print("Division by zero is not allowed.")
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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:

  1. Python kompiliert Source Code zu Bytecode und merkt sich, welcher Handler fuer welchen Bytecode-Bereich zustaendig ist.
  2. Der Interpreter fuehrt den normalen Bytecode-Pfad aus.
  3. Wenn ein Fehler erscheint, sucht Python die aktuelle Bytecode-Position in den Exception-Daten.
  4. Python entfernt nicht mehr relevante Stack-Zustaende und springt zum passenden Handler.
  5. 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.")
Enter fullscreen mode Exit fullscreen mode

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.")
Enter fullscreen mode Exit fullscreen mode

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.


Ursprünglich auf meinem Blog veröffentlicht, wo ich ihn aktuell halte: Immer aktuelle Version lesen →

Ich schreibe über Platform Engineering, Google Cloud und Cloud-Security — auf Deutsch und Englisch. Mehr davon gibt es hier.

Top comments (0)