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

Python Decorators Complete Guide 2026: Muster, Caching und Produktionsverwendung

⏱️5 min read  ·  987 words

Python-Dekoratoren sind eine der elegantesten Funktionen der Sprache. Im Jahr 2026 gibt es Dekoratoren überall – von FastAPI-Routendefinitionen bis hin zu Datenklassen, von der Typprüfung bis hin zu Caching und Wiederholungslogik. Dieser vollständige Leitfaden führt Sie von den Grundlagen bis zum Aufbau Ihrer eigenen Dekorateure in Produktionsqualität.

Was ist ein Dekorateur?

Ein Dekorator ist eine Funktion, die eine andere Funktion umschließt, um Verhalten hinzuzufügen. Der@Syntax ist syntaktischer Zucker:

# These two are equivalent:

@my_decorator
def my_function():
    pass

# Same as:
def my_function():
    pass
my_function = my_decorator(my_function)

# Simple decorator example
def log_calls(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}")
        result = func(*args, **kwargs)
        print(f"Done {func.__name__}")
        return result
    return wrapper

@log_calls
def greet(name: str) -> str:
    return f"Hello, {name}!"

greet("Alice")
# Calling greet
# Done greet

functools.wraps – Metadaten beibehalten

import functools

def my_decorator(func):
    @functools.wraps(func)  # preserves __name__, __doc__, __annotations__
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def add(a: int, b: int) -> int:
    return a + b

print(add.__name__)   # "add" (without wraps, would be "wrapper")
print(add.__doc__)    # preserved docstring

Dekorateur mit Argumenten

import functools, time

# Decorator that accepts arguments uses three levels of nesting
def retry(max_attempts: int = 3, delay: float = 1.0, exceptions: tuple = (Exception,)):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            last_error = None
            for attempt in range(1, max_attempts + 1):
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    last_error = e
                    if attempt < max_attempts:
                        print(f"Attempt {attempt} failed: {e}. Retrying in {delay}s...")
                        time.sleep(delay)
            raise last_error
        return wrapper
    return decorator

@retry(max_attempts=3, delay=0.5, exceptions=(ConnectionError, TimeoutError))
def fetch_data(url: str) -> dict:
    import requests
    return requests.get(url, timeout=5).json()

Klassenbasierte Dekoratoren

import functools
import time
from collections import defaultdict

class RateLimit:
    def __init__(self, calls: int, period: float):
        self.calls = calls
        self.period = period
        self._call_times: list[float] = []

    def __call__(self, func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            now = time.time()
            # Remove calls older than period
            self._call_times = [t for t in self._call_times if now - t < self.period]

            if len(self._call_times) >= self.calls:
                wait_time = self.period - (now - self._call_times[0])
                if wait_time > 0:
                    time.sleep(wait_time)

            self._call_times.append(time.time())
            return func(*args, **kwargs)
        return wrapper

@RateLimit(calls=5, period=1.0)   # max 5 calls per second
def api_request(endpoint: str) -> dict:
    import requests
    return requests.get(f"https://api.example.com{endpoint}").json()

Caching-Dekoratoren

from functools import lru_cache, cache
import time

# Simple memoization (Python 3.9+)
@cache   # unlimited cache size
def fibonacci(n: int) -> int:
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# LRU cache with size limit
@lru_cache(maxsize=128)
def expensive_computation(x: float, y: float) -> float:
    time.sleep(0.1)  # simulate slow computation
    return x ** 2 + y ** 2

# Cache with expiry (custom implementation)
def ttl_cache(ttl_seconds: float):
    def decorator(func):
        cache_store: dict = {}
        cache_times: dict = {}

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            key = (args, tuple(sorted(kwargs.items())))
            now = time.time()

            if key in cache_store and (now - cache_times[key]) < ttl_seconds:
                return cache_store[key]  # return cached

            result = func(*args, **kwargs)
            cache_store[key] = result
            cache_times[key] = now
            return result
        return wrapper
    return decorator

@ttl_cache(ttl_seconds=60)
def get_exchange_rate(currency: str) -> float:
    # Fetches rate from API, cached for 60 seconds
    ...

# Inspect cache stats
print(fibonacci.cache_info())  # CacheInfo(hits=5, misses=10, maxsize=None, currsize=10)
fibonacci.cache_clear()

Dekorateure in FastAPI

from fastapi import FastAPI, Depends, HTTPException, Request
from functools import wraps
import time

app = FastAPI()

# FastAPI uses decorators for routing
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    return {"id": user_id}

# Custom decorator for timing API endpoints
def measure_time(func):
    @wraps(func)
    async def wrapper(*args, **kwargs):
        start = time.perf_counter()
        response = await func(*args, **kwargs)
        duration = time.perf_counter() - start
        print(f"{func.__name__}: {duration*1000:.2f}ms")
        return response
    return wrapper

@app.get("/expensive")
@measure_time
async def expensive_endpoint():
    import asyncio
    await asyncio.sleep(0.1)
    return {"status": "done"}

# Require auth decorator
def require_auth(func):
    @wraps(func)
    async def wrapper(request: Request, *args, **kwargs):
        token = request.headers.get("Authorization", "").replace("Bearer ", "")
        if not token or not validate_token(token):
            raise HTTPException(status_code=401, detail="Unauthorized")
        return await func(request, *args, **kwargs)
    return wrapper

Gängige Dekorationsmuster

import functools, time, logging

logger = logging.getLogger(__name__)

# Timing decorator
def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        logger.debug(f"{func.__name__} took {elapsed*1000:.2f}ms")
        return result
    return wrapper

# Validation decorator
def validate_positive(func):
    @functools.wraps(func)
    def wrapper(value: float, *args, **kwargs):
        if value < 0:
            raise ValueError(f"Expected positive number, got {value}")
        return func(value, *args, **kwargs)
    return wrapper

# Singleton decorator
def singleton(cls):
    instances = {}
    @functools.wraps(cls)
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return get_instance

@singleton
class DatabaseConnection:
    def __init__(self, url: str):
        self.url = url

# Deprecation warning
def deprecated(reason: str = ""):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            import warnings
            msg = f"{func.__name__} is deprecated. {reason}"
            warnings.warn(msg, DeprecationWarning, stacklevel=2)
            return func(*args, **kwargs)
        return wrapper
    return decorator

@deprecated("Use new_function() instead")
def old_function():
    pass

Stapeldekorateure

# Decorators apply bottom-to-top
@retry(max_attempts=3)
@timer
@validate_positive
def compute(value: float) -> float:
    return value ** 2

# Equivalent to:
compute = retry(max_attempts=3)(timer(validate_positive(compute)))

Python-Dekoratoren sind die sauberste Möglichkeit, übergreifende Aspekte wie Protokollierung, Caching, Ratenbegrenzung, Authentifizierung und Wiederholungslogik hinzuzufügen, ohne die Kernfunktion zu ändern. Immer verwenden@functools.wrapsum Metadaten zu bewahren. Erstellen Sie parametrisierte Dekoratoren, wenn Sie konfigurierbares Verhalten benötigen.

✍️ Leave a Comment

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

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