Python Decorators sind eine der elegantesten und mächtigsten Funktionen in der Sprache. Sie erlauben es dir, Funktionen und Klassen auf eine saubere, wiederverwendbare und modulare Art zu erweitern – ohne den eigentlichen Code der Funktionen zu modifizieren. In diesem Blog-Post erfährst du alles über Python Decorators: von der Grundlagen bis hin zu praktischen Beispielen, häufigen Anwendungsfällen und typischen Problemen.
Was sind Python Decorators?
Ein Decorator ist eine Funktion, die eine andere Funktion als Argument entgegennimmt und diese Funktion erweitert oder modifiziert, ohne sie direkt zu verändern. Sie sind ein syntaktisches Zuckerstück in Python, das mit dem @
-Zeichen verwendet wird.
Einfaches Beispiel
def my_decorator(func):
def wrapper():
print("Vor dem Aufruf der Funktion")
func()
print("Nach dem Aufruf der Funktion")
return wrapper
@my_decorator
def say_hello():
print("Hallo Welt!")
say_hello()
Ausgabe:
Vor dem Aufruf der Funktion
Hallo Welt!
Nach dem Aufruf der Funktion
Hier wird say_hello
durch my_decorator
erweitert – ohne den ursprünglichen Code zu verändern.
Typische Anwendungsfälle von Decorators
1. Zeitmessung (Timing)
Ein häufiger Anwendungsfall ist das Messen der Laufzeit einer Funktion:
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} dauerte {end - start:.4f} Sekunden")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
return "Fertig!"
slow_function()
2. Logging
Ein Decorator kann helfen, Funktionen zu loggen:
import functools
def log_calls(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"Aufruf von {func.__name__} mit {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"Ergebnis: {result}")
return result
return wrapper
@log_calls
def add(a, b):
return a + b
add(3, 5)
Ausgabe:
Aufruf von add mit (3, 5), {}
Ergebnis: 8
3. Authentifizierung (z. B. für Web-APIs)
def require_auth(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Simuliere eine Authentifizierung
if not hasattr(wrapper, 'authenticated') or not wrapper.authenticated:
raise PermissionError("Authentifizierung erforderlich")
return func(*args, **kwargs)
return wrapper
@require_auth
def sensitive_data():
return "Vertrauliche Daten"
# Ohne Authentifizierung:
# sensitive_data() # -> Fehler
Decorators mit Parametern
Manchmal will man einen Decorator auch mit Parametern verwenden. Das geht so:
def repeat(times):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def greet(name):
print(f"Hallo {name}")
greet("Peter")
Ausgabe:
Hallo Peter
Hallo Peter
Hallo Peter
Wichtige Probleme und Fallstricke
1. Verlust von Funktionsmetadaten
Wenn du Decorators ohne functools.wraps
schreibst, verlieren deine Funktionen Informationen wie __name__
, __doc__
, etc.
Problem:
def my_decorator(func):
def wrapper():
return func()
return wrapper
@my_decorator
def example():
"""Das ist eine Beispiel-Funktion"""
pass
print(example.__name__) # Gibt "wrapper" aus, nicht "example"
Lösung:
Nutze @functools.wraps(func)
:
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper():
return func()
return wrapper
2. Decorators bei Klassen
Decorators funktionieren auch mit Klassen. Ein Beispiel für einen Klassendecorator:
def add_method(cls):
def new_method(self):
return "Neue Methode hinzugefügt!"
cls.new_method = new_method
return cls
@add_method
class MyClass:
pass
obj = MyClass()
print(obj.new_method()) # "Neue Methode hinzugefügt!"
3. Reihenfolge von Decorators
Die Reihenfolge der Decorators ist wichtig. Sie werden von unten nach oben angewendet:
@decorator1
@decorator2
def my_function():
pass
decorator2
wird zuerst auf my_function
angewendet, dann decorator1
.
Fazit
Python Decorators sind ein mächtiges Werkzeug, mit dem du Funktionen und Klassen elegant erweitern kannst. Sie sind besonders nützlich für:
- Logging
- Timing
- Authentifizierung
- Caching
- Validierung
Doch Achtung: Mit großer Macht kommt auch große Verantwortung. Achte darauf, Metadaten mit functools.wraps
zu bewahren und die Reihenfolge der Decorators zu verstehen.