🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

Python-Dekoratoren erklärt: Der vollständige Leitfaden für 2026

⏱️7 min read  ·  1,469 words


Python Decorators Explained: The Complete 2026 Guide

TechPulse-Redaktion
Technische Autoren · 24. Mai 2026
📅 24. Mai 2026⏱ 14 Min. Lektüre📂 Programmierung🏷 Python · Dekorateure · Advanced-Python

Was ist ein Python-Dekorator?

A Python-Dekorateurist ein Entwurfsmuster, mit dem Sie einer vorhandenen Funktion neues Verhalten hinzufügen können – ohne den Code der Funktion zu berühren. In Python sind Funktionen erstklassige Objekte: Sie können als Argumente übergeben, Variablen zugewiesen und von anderen Funktionen zurückgegeben werden. Dekorateure nutzen diese Eigenschaft.

Der@Syntax ist nur syntaktischer Zucker. Wenn Sie schreiben:

@my_decorator
def greet(name):
    return f"Hello, {name}!"

Python führt tatsächlich Folgendes aus:

greet = my_decorator(greet)

Der Dekorateur übernimmt die ursprüngliche Funktion, verpackt sie in eine neue Funktion mit zusätzlichem Verhalten und gibt sie zurück. Der Namegreetzeigt nun auf die erweiterte Version.

Ihr erster Dekorateur: Schritt für Schritt

Lassen Sie uns ein einfaches erstellenLogging-Dekorateurdas eine Nachricht vor und nach dem Aufruf einer Funktion ausgibt.

def log_calls(func):
    """Decorator that logs function entry and exit."""
    def wrapper(*args, **kwargs):
        print(f"→ Calling {func.__name__} with args={args}, kwargs={kwargs}")
        result = func(*args, **kwargs)
        print(f"← {func.__name__} returned {result!r}")
        return result
    return wrapper

@log_calls
def add(a, b):
    return a + b

add(3, 4)
# Output:
# → Calling add with args=(3, 4), kwargs={}
# ← add returned 7

Aufschlüsselung:

  • log_callserhältfunc(die ursprüngliche Funktion)
  • Es definiert ein Innereswrapperdas akzeptiert*args, **kwargs– es funktioniert also mit jeder Funktionssignatur
  • Der Wrapper ruft das Original auffunc, erfasst das Ergebnis und gibt es zurück
  • log_callsgibt den Wrapper zurück – nicht das Ergebnis des Aufrufs

Der functools.wraps Fix

Es gibt einen subtilen Fehler im Dekorator oben. Nach der Dekoration,add.__name__kehrt zurück'wrapper', nicht'add'. Das geht kaputthelp(), inspectund Stapelspuren. Repariere es mitfunctools.wraps:

import functools

def log_calls(func):
    @functools.wraps(func)   # ← copies __name__, __doc__, __module__, etc.
    def wrapper(*args, **kwargs):
        print(f"→ Calling {func.__name__}")
        result = func(*args, **kwargs)
        print(f"← {func.__name__} returned {result!r}")
        return result
    return wrapper

@log_calls
def add(a, b):
    """Add two numbers."""
    return a + b

print(add.__name__)   # 'add'  ✅
print(add.__doc__)    # 'Add two numbers.'  ✅
⚠ Regel:Immer verwenden@functools.wraps(func)in jedem Dekorateur, den du schreibst. Das Überspringen führt zu mysteriösen Fehlern in der Protokollierung, den Test-Frameworks und den API-Dokumentationstools.

Dekorateure mit Argumenten

Was ist, wenn Sie Ihren Dekorateur konfigurieren möchten? Zum Beispiel,@retry(times=3). Sie benötigen eine zusätzliche Verschachtelungsebene – aDekorateurfabrik:

import functools, time

def retry(times=3, delay=1.0, exceptions=(Exception,)):
    """Retry a function up to `times` times on specified exceptions."""
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            last_err = None
            for attempt in range(1, times + 1):
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    last_err = e
                    print(f"   Attempt {attempt}/{times} failed: {e}")
                    if attempt < times:
                        time.sleep(delay)
            raise last_err
        return wrapper
    return decorator

@retry(times=3, delay=0.5, exceptions=(ConnectionError,))
def fetch_data(url):
    # simulate a flaky network call
    raise ConnectionError("timeout")

try:
    fetch_data("https://api.example.com/data")
except ConnectionError:
    print("All retries exhausted.")

Die dreistufige Struktur:retry()decorator()wrapper(). Nennen Sie es:retry(times=3)kehrt zurückdecorator, was dauertfuncund kehrt zurückwrapper.

Mehrere Dekoratoren stapeln

Sie können mehrere Dekoratoren auf eine einzelne Funktion anwenden. Sie geltenvon unten nach oben(das Innerste zuerst):

import functools, time

def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"{func.__name__} took {elapsed:.4f}s")
        return result
    return wrapper

def log_calls(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@timer          # applied second (outer)
@log_calls      # applied first (inner)
def process(n):
    return sum(range(n))

process(1_000_000)
# Output:
# Calling process
# process took 0.0312s

Entspricht:process = timer(log_calls(process)). Ordnung ist wichtig – äußere Dekorateure wickeln innere ein.

Klassenbasierte Dekoratoren

Jedes aufrufbare Objekt kann ein Dekorator sein. Durch die Verwendung einer Klasse erhalten Sie einen Status zwischen Aufrufen:

import functools

class CallCounter:
    """Counts how many times a function is called."""
    def __init__(self, func):
        functools.update_wrapper(self, func)
        self.func = func
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"{self.func.__name__} called {self.count} time(s)")
        return self.func(*args, **kwargs)

@CallCounter
def say_hello(name):
    print(f"Hello, {name}!")

say_hello("Alice")   # called 1 time(s)
say_hello("Bob")     # called 2 time(s)
print(say_hello.count)  # 2

@staticmethod vs. @classmethod vs. @property

Python wird mit mehreren integrierten Dekoratoren ausgeliefert, die Sie ständig verwenden werden:

class Temperature:
    _kelvin_offset = 273.15

    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def fahrenheit(self):
        """Computed attribute — no () needed when accessing."""
        return self._celsius * 9/5 + 32

    @fahrenheit.setter
    def fahrenheit(self, value):
        self._celsius = (value - 32) * 5/9

    @classmethod
    def from_kelvin(cls, kelvin):
        """Factory method — creates instance from Kelvin."""
        return cls(kelvin - cls._kelvin_offset)

    @staticmethod
    def is_valid_celsius(value):
        """Utility — no access to instance or class."""
        return value >= -273.15

t = Temperature(100)
print(t.fahrenheit)                      # 212.0  (property)
t.fahrenheit = 32                        # setter
t2 = Temperature.from_kelvin(373.15)    # classmethod
print(Temperature.is_valid_celsius(-300))  # False (staticmethod)
Dekorateur Erstes Argument Zugang Anwendungsfall
@property self Instanz + Klasse Berechnete Attribute, Getter/Setter
@classmethod cls Nur Klasse Factory-Methoden, alternative Konstruktoren
@staticmethod Keiner Weder Dienstprogrammfunktionen mit Namensraum für die Klasse

Anwendungsfälle aus der Praxis

Dekoratoren unterstützen die meisten Python-Frameworks. Hier sind Muster in Produktionsqualität:

1. Caching mit LRU-Cache

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(50))  # Instant — cached results
print(fibonacci.cache_info())  # CacheInfo(hits=48, misses=51, ...)

2. Authentifizierungsschutz (Flask/FastAPI-Stil)

import functools

def require_auth(func):
    """Decorator for protected routes."""
    @functools.wraps(func)
    def wrapper(request, *args, **kwargs):
        token = request.headers.get("Authorization", "")
        if not token.startswith("Bearer "):
            return {"error": "Unauthorized"}, 401
        return func(request, *args, **kwargs)
    return wrapper

@require_auth
def get_user_profile(request):
    return {"user": "Alice", "email": "alice@example.com"}

3. Ratenbegrenzer

import functools, time
from collections import defaultdict, deque

def rate_limit(calls=10, period=60):
    """Allow at most `calls` per `period` seconds per caller."""
    history = defaultdict(deque)
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            now = time.time()
            key = args[0] if args else "default"  # use first arg as caller ID
            q = history[key]
            while q and now - q[0] > period:
                q.popleft()
            if len(q) >= calls:
                raise RuntimeError(f"Rate limit exceeded: {calls} calls per {period}s")
            q.append(now)
            return func(*args, **kwargs)
        return wrapper
    return decorator

@rate_limit(calls=5, period=60)
def send_email(user_id, message):
    print(f"Email sent to {user_id}: {message}")

Häufige Fehler, die es zu vermeiden gilt

  • Vergessen@functools.wraps– Pausenhelp(), Tracebacks und Testtools
  • Aufrufen der Funktion im Dekoratorkörperreturn wrapper()anstattreturn wrapper
  • Wird nicht verwendet*args, **kwargs– unterbricht jede Funktion mit Parametern
  • Veränderbarer Standardstatus, der von allen Aufrufen gemeinsam genutzt wird– Verwenden Sie eine Abschlussvariable, keinen veränderbaren Standardwert auf Modulebene
  • Fehlenreturn resultim Umschlag– verschluckt stillschweigend den Rückgabewert der Funktion

# ❌ Wrong — returns None
def broken(func):
    def wrapper(*args, **kwargs):
        func(*args, **kwargs)   # no return!
    return wrapper

# ✅ Correct
def fixed(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)  # always return
    return wrapper

🚀 Verbessern Sie Ihre Python-Kenntnisse

Nachdem Sie nun Dekoratoren verstanden haben, erkunden Sie, wie sie Frameworks unterstützenStrukturierung von Python-Projektenund fortgeschrittene Muster. Schauen Sie sich unseren Leitfaden anPython-Kurzausdrückefür weitere Pythonic-Code-Tricks.

Häufig gestellte Fragen

Was ist ein Python-Dekorator?

Ein Python-Dekorator ist eine Funktion, die eine andere Funktion als Eingabe verwendet und eine erweiterte Version zurückgibt – ohne das Original zu ändern. Der@Syntax ist eine Abkürzung fürfunc = decorator(func).

Wann sollte ich Dekorateure einsetzen?

Verwenden Sie Dekoratoren für übergreifende Anliegen: Protokollierung, Caching, Authentifizierung, Ratenbegrenzung, Timing, Eingabevalidierung – jedes Verhalten, das Sie auf mehrere Funktionen anwenden möchten, ohne Code zu wiederholen.

Was macht functools.wraps?

Es kopiert die Originalfunktionen__name__, __doc__und andere Attribute für den Wrapper, wobei die Identität für Debugging-, help()- und Testtools erhalten bleibt.

Können Dekorateure argumentieren?

Ja. Fügen Sie eine äußere Factory-Funktion hinzu, die die Argumente akzeptiert und den echten Dekorator zurückgibt. Muster:@retry(times=3)retry()gibt den Dekorateur zurück.

Was ist der Unterschied zwischen @staticmethod und @classmethod?

@staticmethoderhält kein implizites erstes Argument – ​​es ist eine einfache Funktion in einem Klassennamensraum.@classmethoderhält die Klasse (cls) als erstes Argument, nützlich für Factory-Methoden.

Wie funktionieren gestapelte Dekoratoren?

Von unten nach oben: der Dekorateur, der dem am nächsten istdefwird zuerst angewendet.@A @B def f()gleichtf = A(B(f)).

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা