Dekoratoren sind Funktionen, die eine andere Funktion annehmen und eine neue Funktion mit erweitertem oder verändertem Verhalten zurückgeben. Sie werden häufig für Protokollierung, Berechtigungsprüfung, Caching, Laufzeit und mehr verwendet.
Dekoratoren werden mithilfe von Closures oder Klassen umgesetzt, die die Methode __call__ implementieren. Die klassische Syntax:
# Einfacher Dekorator def simple_decorator(func): def wrapper(*args, **kwargs): print("Vor dem Funktionsaufruf") result = func(*args, **kwargs) print("Nach dem Funktionsaufruf") return result return wrapper @simple_decorator def my_func(): print("Hauptfunktion") my_func()
Das Ergebnis wird so aussehen:
Vor dem Funktionsaufruf
Hauptfunktion
Nach dem Funktionsaufruf
Hauptnutzen — Kapselung von wiederkehrender Logik außerhalb der eigentlichen Geschäftsanwendung.
Feinheiten:
functools.wraps geht der Name der ursprünglichen Funktion und ihr Docstring verloren.Frage: "Wenn ich eine Funktion mit einem Dekorator dekoriere und dann versuche, den Namen der Funktion über __name__ zu erhalten, was werde ich sehen und wie kann ich den Originalnamen beibehalten?"
Antwort:
Standardmäßig ändert sich der Name auf den Namen der Wrapper-Funktion (normalerweise wrapper). Um die ursprünglichen Metadaten zu erhalten, verwenden Sie functools.wraps:
import functools def dec(f): @functools.wraps(f) def wrapper(*args): return f(*args) return wrapper @dec def foo(): pass print(foo.__name__) # gibt 'foo' aus, nicht 'wrapper'
Geschichte
In einer großen Ressourcenautomatisierung brach das System für automatisierte Tests, das Reflexion über die Namen der Testfunktionen verwendete, nach dem Dekorieren der Funktionen zusammen. Das Problem war das Fehlen von functools.wraps.
Geschichte
Ein Dekorator, der Logging hinzufügte, unterstützte keine Funktionen mit unterschiedlichen Signaturen, da *args, **kwargs nicht verwendet wurden. Ein Teil der Funktionen brach einfach stillschweigend ab.
Geschichte
In einem Projekt mit Authentifizierung in der REST API implementierte der Entwickler einen Dekorator mit Parametern, vergaß jedoch, die Funktionen korrekt zu verschachteln (es gab eine zweistufige Verschachtelung anstelle von drei). Infolgedessen konnte der Dekorator keine Parameter annehmen.