Nutze Funktionen als First-Class-Objekte, um robuste, parametrierbare und transparente Dekoratoren zu schreiben.
Diese Lektion in Kodokon öffnenIn Python ist eine Funktion ein Objekt wie jedes andere: Du kannst sie einer Variablen zuweisen, als Argument übergeben, zurückgeben. Eine Funktion höherer Ordnung nimmt eine Funktion entgegen oder gibt eine zurück - sorted(data, key=...) ist eine davon. Nimm noch Closures hinzu, bei denen eine innere Funktion die Variablen der umschließenden Funktion einfängt und sie über deren Rückkehr hinaus am Leben hält, und du hast alle Zutaten für Dekoratoren.
def make_multiplier(factor):
def multiply(value):
return value * factor
return multiply
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(10), triple(10)) # 20 30Ein Dekorator ist eine Funktion, die eine Funktion entgegennimmt und eine andere zurückgibt - meist einen wrapper, der Verhalten um den Aufruf herum ergänzt. Die Syntax @timed über def slow_sum ist reiner Zucker für slow_sum = timed(slow_sum). Der Wrapper akzeptiert *args, kwargs, um gegenüber der Signatur agnostisch zu bleiben, und gibt das Ergebnis der dekorierten Funktion zurück** - das zu vergessen ist ein klassischer Fehler, der jeden Rückgabewert in None verwandelt.
import functools
import time
def timed(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
delay = time.perf_counter() - start
print(f"{func.__name__}: {delay:.4f}s")
return result
return wrapper
@timed
def slow_sum(n):
return sum(range(n))
print(slow_sum(1_000_000))Um einen Dekorator zu parametrieren (@repeat(times=3)), brauchst du eine Ebene mehr: eine Factory, die die Parameter entgegennimmt und den Dekorator zurückgibt, der seinerseits den Wrapper zurückgibt. Drei verschachtelte Funktionen - das ist der Preis der Flexibilität. Wenn der Zustand komplex wird, ist eine Klasse mit einer __call__-Methode oft lesbarer. Reserviere Dekoratoren für Querschnittsbelange: Logging, Caching, Retry, Zugriffskontrolle. Ein Dekorator, der die Geschäftslogik verändert, verbirgt das Wesentliche vor dem Leser.
import functools
def repeat(times):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
result = None
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def greet(name):
print(f"Hello {name}")
greet("Ada")