Python-Dekoratoren erklärt: Von @property zur Retry-Logik in 15 Minuten (2026)
Dekoratoren sind die Funktion, die „kennt Python“ von „liest Python fließend“ unterscheidet. Sie sehen magisch aus, sind aber mechanisch: „@decorator“ für eine Funktion ist genau „f = decorator(f)“. Das ist es. Alles andere in diesem Tutorial besteht darin, dass eine Linie in verschiedenen Formen aufgetragen wird.
Die Einlinientheorie
Wenn Sie schreiben:
Python wandelt es um in:
Das ist die gesamte Mechanik. „@decorator_name“ über einem „def“ führt „def_name = decorator_name(def_name)“ nach der Definition aus. Wenn Sie dies verinnerlichen, hören Dekorateure für immer auf, mysteriös zu sein.
Schreiben Sie Ihren ersten Dekorateur (60 Sekunden)
Ein Dekorator ist ein beliebiger Callable, der eine Funktion annimmt und eine Funktion zurückgibt. Die typische Form:
Das „args, *kwargs“ im Wrapper ist ein defensives Muster – es ermöglicht dem Dekorateur, unabhängig von der Signatur an jeder Funktion zu arbeiten. Wenn Sie es überspringen, erhalten Sie die Meldung „TypeError: Wrapper() nimmt 0 Positionsargumente, aber 2 wurden angegeben“, sobald jemand eine Funktion mit Parametern dekoriert.
Der „@functools.wraps“-Fix
Ein subtiler Fehler: Nach dem Dekorieren ist „add.__name__“ „wrapper“ und nicht „add“. Docstrings und Typhinweise verschwinden ebenfalls. Die Lösung ist ein Import:
Regel: Jeder Dekorator, den Sie schreiben, sollte „@functools.wraps(fn)“ verwenden. Es kostet eine Zeile und verhindert eine ganze Kategorie von Debugging-Schmerzen (Introspektion, „Pytest“-Fixtures, „Logging“-Formatierer, „Pickle“ – alles bricht ohne es stillschweigend ab).
Die vier Dekoratoren, die Sie in jeder Codebasis sehen
1. „@property“ – berechnete Attribute
„@property“ macht eine Methode aufrufbar, als wäre sie ein Attribut. Perfekt für schreibgeschützte abgeleitete Werte. Es gibt auch „@area.setter“ für den Schreibpfad, aber 90 % der Verwendungen von „@property“ sind schreibgeschützt.
2. „@staticmethod“ und „@classmethod“.
„@classmethod“ erhält „cls“ (die Klasse selbst) und wird für alternative Konstruktoren verwendet. „@staticmethod“ hat nichts Besonderes und ist eine einfache Funktion, die sich zufällig im Klassennamensraum befindet.
3. „@functools.cache“ – Auswendiglernen
Einer der leistungsstärksten Stdlib-Dekoratoren. Merkt sich die Funktion automatisch basierend auf ihren Argumenten. Erfordert, dass alle Argumente hashbar sind (keine Listen/Diktate als Argumente – Tupel verwenden).
4. „@dataclasses.dataclass“ – Eliminierung von Boilerplates
„@dataclass“ liest die Typanmerkungen auf Klassenebene und generiert automatisch „__init__“, „__repr__“, „__eq__“ und (mit „frozen=True“). Dies ist die größte Verbesserung der Lebensqualität in Python 3.7+.
Schreiben eines „@retry“-Dekorators (Beispiel aus der Praxis)
Ein Dekorator, der eine Funktion bei einem Fehler mit exponentiellem Backoff wiederholt:
Beachten Sie die drei verschachtelten Funktionen: „retry“ akzeptiert die Konfigurationsargumente und gibt „decorator“ zurück; „decorator“ akzeptiert die Funktion und gibt „wrapper“ zurück; „wrapper“ führt die Wiederholungsschleife aus. Dieses dreischichtige Muster sieht aus wie jeder Dekorateur mit Argumenten – merken Sie sich die Form, nicht das konkrete Beispiel.
Klassenbasierte Dekoratoren (selten, aber nützlich)
Ein Dekorateur ist jeder rufbar. Klassen mit „__call__“ funktionieren auch:
Wird verwendet, wenn der Dekorateur einen Zustand halten muss, der einen einzelnen Aufruf überdauert (ein Zähler, ein Cache, ein Rate-Limit-Bucket).
Häufige Fallstricke
1. ** „@functools.wraps“ vergessen – die Selbstbeobachtung bricht stillschweigend ab.
2. Veränderliche Standardargumente im Dekorator selbst – der klassische „def wrapper(x, Cache=[])“-Fehler sticht auch hier hervor.
3. Methoden dekorieren, ohne „Selbst“ zu akzeptieren – denken Sie daran, dass „Selbst“ nur ein Positionsargument ist; „args, *kwargs“ fängt es gut ein.
4. Auf die Reihenfolge beim Stapeln kommt es an: „@a\n@b\ndef f()“ ist „f = a(b(f))“. Lesen Sie die Stapel von unten nach oben.
Üben
Schreiben Sie einen „@timing“-Dekorator, der ausgibt, wie lange die Ausführung der umschlossenen Funktion dauert, und wenden Sie ihn dann auf eine Funktion an, die „sum(range(10_000_000))“ berechnet. Der gesamte Dekorator besteht aus 8 Zeilen mit „functools.wraps“ + „time.perf_counter“.
Sobald Sie verinnerlicht haben, dass „@x“ „f = x(f)“ ist, werden Dekoratoren zu einer der produktivsten Funktionen von Python. Sie sind überall in echten Codebasen: Flask/FastAPI-Routen („@app.route“), Pytest-Fixtures („@pytest.fixture“), Django-Ansichten („@login_required“), Pydantic-Validatoren („@field_validator“). Wenn Sie lernen, sie selbst zu schreiben, können Sie sie alle lesen.
Nächster Schritt: 10 praktische Lektionen zum Dekorieren – Erstellen Sie „@retry“, „@memoise“, „@rate_limit“ und „@requires_auth“ von Grund auf mit echtem Python, das in Ihrem Browser ausgeführt wird.