Python-Dekoratoren: Ein umfassender Leitfaden
Als ich anfing, mit Python zu programmieren, war die Version, wenn ich mich nicht irre, 3.3. Als ich mit dem Programmieren begann, standen der Python-Community daher schon lange Dekoratoren zur Verfügung.
Funktionsdekoratoren kamen mit Version 2.2 zu Python und Klassendekoratoren kamen mit Version 2.6 zu Python.
Ich persönlich halte die Decorator-Funktion von Python für eine sehr leistungsstarke Funktion der Sprache.
Eigentlich ist es mein Ziel, eine Reihe von Artikeln über die am schwierigsten zu verstehenden Themen in Python zu verfassen. Ich habe vor, diese Themen, die etwas mehr als zehn sind, einzeln zu behandeln.
In diesem Artikel werde ich versuchen, jeden Teil des Themas Dekorateure so weit wie möglich anzusprechen.
1. Historischer Kontext
- Anfänge (Pre-Python 2.2): Vor Dekoratoren erforderte das Ändern von Funktionen oder Klassen oft manuelles Umschließen oder Monkey-Patching, was umständlich und weniger lesbar war.
- Metaklassen (Python 2.2): Metaklassen boten eine Möglichkeit, die Klassenerstellung zu steuern und boten einige der Funktionen, die Dekoratoren später bereitstellen würden, waren jedoch für einfache Änderungen komplex.
- PEP 318 (Python 2.4): Dekoratoren wurden offiziell in Python 2.4 durch PEP 318 eingeführt. Der Vorschlag wurde von Annotationen in Java inspiriert und zielte darauf ab, eine sauberere, deklarativere Möglichkeit zum Ändern von Funktionen und Methoden bereitzustellen .
- Klassendekoratoren (Python 2.6): Python 2.6 hat die Unterstützung von Dekoratoren für Klassen erweitert und so deren Vielseitigkeit weiter verbessert.
- Weit verbreitete Akzeptanz: Dekoratoren wurden schnell zu einer beliebten Funktion, die in Frameworks wie Flask und Django häufig für Routing, Authentifizierung und mehr verwendet wird.
2. Was sind Dekorateure?
Im Wesentlichen ist ein Dekorator ein Entwurfsmuster in Python, mit dem Sie das Verhalten einer Funktion oder einer Klasse ändern können, ohne deren Kernstruktur zu ändern. Dekoratoren sind eine Form der Metaprogrammierung, bei der Sie im Wesentlichen Code schreiben, der anderen Code manipuliert.
Sie wissen, dass Python Namen mithilfe des in der folgenden Reihenfolge angegebenen Bereichs auflöst:
- Lokal
- Umschließen
- Global
- Eingebaut
Dekorateure sind ein umschließender Bereich, der eng mit dem Verschlusskonzept zusammenhängt.
Schlüsselidee: Ein Dekorateur nimmt eine Funktion als Eingabe, fügt ihr einige Funktionen hinzu und gibt eine modifizierte Funktion zurück.
Analogie: Stellen Sie sich einen Dekorateur als Geschenkverpackung vor. Sie haben ein Geschenk (die ursprüngliche Funktion) und verpacken es mit dekorativem Papier (der Dekorateur), um es schöner aussehen zu lassen oder zusätzliche Funktionen hinzuzufügen (z. B. eine Schleife oder eine Karte). Das darin enthaltene Geschenk bleibt dasselbe, aber seine Präsentation oder die damit verbundenen Aktionen werden verbessert.
A) Dekorator-Variationen: funktionsbasiert vs. klassenbasiert
Die meisten Dekoratoren in Python werden mithilfe von Funktionen implementiert, Sie können Dekoratoren jedoch auch mithilfe von Klassen erstellen.
Funktionsbasierte Dekoratoren sind häufiger und einfacher, während klassenbasierte Dekoratoren zusätzliche Flexibilität bieten.
Funktionsbasierte grundlegende Decorator-Syntax
def my_decorator(func): def wrapper(*args, **kwargs): # Do something before calling the decorated function print("Before function call") result = func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result return wrapper @my_decorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
Erklärung:
- my_decorator ist die Dekoratorfunktion. Es benötigt die zu dekorierende Funktion func als Eingabe.
- Wrapper ist eine innere Funktion, die den Aufruf der ursprünglichen Funktion umschließt. Es kann Code vor und nach der ursprünglichen Funktion ausführen.
- @my_decorator ist die Decorator-Syntax. Es entspricht say_hello = my_decorator(say_hello).
Klassenbasierte grundlegende Decorator-Syntax
Diese verwenden Klassen anstelle von Funktionen, um Dekoratoren zu definieren.
class MyDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): # Do something before calling the decorated function print("Before function call") result = self.func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result @MyDecorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
Erklärung:
- MyDecorator ist eine Klasse, die als Dekorateur fungiert.
- Die __init__-Methode speichert die zu dekorierende Funktion.
- Die Methode __call__ macht die Klasseninstanz aufrufbar, sodass sie wie eine Funktion verwendet werden kann.
B) Implementierung eines einfachen Dekorators
Das grundlegende Konzept von Dekoratoren besteht darin, dass es sich um Funktionen handelt, die eine andere Funktion als Argument verwenden und deren Verhalten erweitern, ohne sie explizit zu ändern.
Hier ist die einfachste Form:
def my_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper # Using the decorator with @ syntax @my_decorator def say_hello(): print("Hello!") # When we call say_hello() say_hello() # This is equivalent to: # say_hello = my_decorator(say_hello)
C) Implementieren eines Dekorators mit Argumenten
Lassen Sie uns einen Dekorator erstellen, der die Ausführungszeit einer Funktion protokolliert:
def decorator_with_args(func): def wrapper(*args, **kwargs): # Accept any number of arguments print(f"Arguments received: {args}, {kwargs}") return func(*args, **kwargs) # Pass arguments to the original function return wrapper @decorator_with_args def greet(name, greeting="Hello"): print(f"{greeting}, {name}!") greet("Alice", greeting="Hi") # Prints arguments then "Hi, Alice!"
D) Implementierung eines parametrisierten Dekorators
Dies sind Dekorateure, die ihre eigenen Parameter akzeptieren können:
def repeat(times): def decorator(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"Hello {name}") return "Done" greet("Bob") # Prints "Hello Bob" three times
E) Implementierung eines Klassendekorators
def singleton(cls): instances = {} 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): print("Initializing database connection") # Creating multiple instances actually returns the same instance db1 = DatabaseConnection() # Prints initialization db2 = DatabaseConnection() # No initialization printed print(db1 is db2) # True
F) Implementieren von Methodendekoratoren
Diese sind speziell für Klassenmethoden konzipiert:
def debug_method(func): def wrapper(self, *args, **kwargs): print(f"Calling method {func.__name__} of {self.__class__.__name__}") return func(self, *args, **kwargs) return wrapper class MyClass: @debug_method def my_method(self, x, y): return x + y obj = MyClass() print(obj.my_method(5, 3))
G) Implementieren der Decorator-Verkettung
Mehrere Dekoratoren können auf eine einzelne Funktion angewendet werden:
def bold(func): def wrapper(): return "<b>" + func() + "</b>" return wrapper def italic(func): def wrapper(): return "<i>" + func() + "</i>" return wrapper @bold @italic def greet(): return "Hello!" print(greet()) # Outputs: <b><i>Hello!</i></b>
Erklärung:
- Dekorationen werden von unten nach oben aufgetragen.
- Es ist eher so, wie wir es in der Mathematik machen: f(g(x)).
- Zuerst wird Kursivschrift und dann Fettschrift angewendet.
H) Was passiert, wenn wir @functools.wraps nicht verwenden?
Der functools.wraps-Dekorator, siehe Dokumente, ist eine Hilfsfunktion, die die Metadaten der ursprünglichen Funktion (wie Name, Dokumentzeichenfolge und Signatur) beibehält, wenn Sie sie mit einem Dekorator umschließen. Wenn Sie es nicht verwenden, gehen diese wichtigen Informationen verloren.
Beispiel:
def my_decorator(func): def wrapper(*args, **kwargs): """Wrapper docstring""" return func(*args, **kwargs) return wrapper @my_decorator def my_function(): """My function docstring""" pass print(my_function.__name__) print(my_function.__doc__)
Ausgabe:
wrapper Wrapper docstring
Problem:
- Der Name der ursprünglichen Funktion (my_function) und die Dokumentzeichenfolge („Dokumentzeichenfolge meiner Funktion“) gehen verloren.
- Dies kann das Debuggen und die Selbstbeobachtung erschweren.
Lösung: Verwenden Sie functools.wraps):
def my_decorator(func): def wrapper(*args, **kwargs): # Do something before calling the decorated function print("Before function call") result = func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result return wrapper @my_decorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
Ausgabe:
class MyDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): # Do something before calling the decorated function print("Before function call") result = self.func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result @MyDecorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
Vorteile von functools.wraps:
- Behält Funktionsmetadaten bei.
- Verbessert die Lesbarkeit und Wartbarkeit des Codes.
- Erleichtert das Debuggen.
- Hilft bei Selbstbeobachtungstools und Dokumentationsgeneratoren.
I) Dekorateure mit Staat
Dekoratoren können den Status auch zwischen Funktionsaufrufen beibehalten. Dies ist besonders nützlich für Szenarien wie Caching oder Zählen von Funktionsaufrufen.
def my_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper # Using the decorator with @ syntax @my_decorator def say_hello(): print("Hello!") # When we call say_hello() say_hello() # This is equivalent to: # say_hello = my_decorator(say_hello)
Ausgabe:
def decorator_with_args(func): def wrapper(*args, **kwargs): # Accept any number of arguments print(f"Arguments received: {args}, {kwargs}") return func(*args, **kwargs) # Pass arguments to the original function return wrapper @decorator_with_args def greet(name, greeting="Hello"): print(f"{greeting}, {name}!") greet("Alice", greeting="Hi") # Prints arguments then "Hi, Alice!"
Erklärung:
Die Wrapper-Funktion verwaltet einen Zähler (Aufrufe), der jedes Mal erhöht wird, wenn die dekorierte Funktion aufgerufen wird.
Dies ist ein einfaches Beispiel dafür, wie Dekoratoren verwendet werden können, um den Zustand aufrechtzuerhalten.
J) Best Practices für Python-Dekorateure
- Verwenden Sie functools.wraps: Verwenden Sie in Ihren Dekoratoren immer @functools.wraps, um die Metadaten der ursprünglichen Funktion beizubehalten.
- Halten Sie Dekorateure einfach: Dekorateure sollten idealerweise eine bestimmte Sache tun und es gut machen. Dadurch sind sie wiederverwendbar und leichter zu verstehen.
- Dokumentieren Sie Ihre Dekorateure: Erklären Sie, was Ihr Dekorateur tut, welche Argumente er benötigt und was er zurückgibt.
- Testen Sie Ihre Dekorateure: Schreiben Sie Unit-Tests, um sicherzustellen, dass Ihre Dekorateure in verschiedenen Szenarien wie erwartet funktionieren.
- Berücksichtigen Sie die Reihenfolge der Verkettung: Achten Sie beim Verketten mehrerer Dekoratoren auf die Reihenfolge, da diese sich auf den Ausführungsfluss auswirkt.
K) Schlechte Implementierungen (Anti-Patterns)
- Zu komplexe Dekoratoren: Vermeiden Sie es, zu komplexe Dekoratoren zu erstellen oder zu viele Dinge zu tun. Dadurch sind sie schwer zu verstehen, zu warten und zu debuggen.
- Ignorieren von functools.wraps: Das Vergessen, @functools.wraps zu verwenden, führt zum Verlust von Funktionsmetadaten, was zu Problemen bei der Selbstbeobachtung und beim Debuggen führen kann.
- Nebenwirkungen: Dekorateure sollten im Idealfall keine unbeabsichtigten Nebenwirkungen haben, die über die Änderung der dekorierten Funktion hinausgehen.
- Hardcodierung von Werten: Vermeiden Sie die Hardcodierung von Werten innerhalb von Dekoratoren. Verwenden Sie stattdessen Decorator-Fabriken, um sie konfigurierbar zu machen.
- Argumente werden nicht ordnungsgemäß behandelt: Stellen Sie sicher, dass Ihre Wrapper-Funktion eine beliebige Anzahl von Positions- und Schlüsselwortargumenten mit *args und **kwargs verarbeiten kann, wenn der Dekorator mit einer Vielzahl von Funktionen verwendet werden soll.
L) 10. Anwendungsfälle aus der Praxis
- Protokollierung: Aufzeichnen von Funktionsaufrufen, Argumenten und Rückgabewerten zum Debuggen oder Überwachen.
- Timing: Messung der Ausführungszeit von Funktionen zur Leistungsanalyse.
- Caching: Speichern der Ergebnisse teurer Funktionsaufrufe, um redundante Berechnungen zu vermeiden (Memoisierung).
- Authentifizierung und Autorisierung: Überprüfung der Benutzeranmeldeinformationen oder -berechtigungen vor dem Ausführen einer Funktion.
- Eingabevalidierung:Überprüfen, ob die an eine Funktion übergebenen Argumente bestimmte Kriterien erfüllen.
- Ratenbegrenzung: Steuerung der Häufigkeit, mit der eine Funktion innerhalb eines bestimmten Zeitraums aufgerufen werden kann.
- Wiederholungslogik: Automatischer Wiederholungsversuch eines Funktionsaufrufs, wenn dieser aufgrund eines vorübergehenden Fehlers fehlschlägt.
- Framework-spezifische Aufgaben: Frameworks wie Flask und Django verwenden Dekoratoren für das Routing (Zuordnung von URLs zu Funktionen), die Registrierung von Plugins und mehr.
M) Kuratierte Listen von Python-Dekoratoren
Eine kuratierte Liste von Python-Dekoratoren finden Sie unten:
- Tolle Python-Dekoratoren
- Python Decorator-Bibliothek
N) 11. Fazit
Dekoratoren sind eine leistungsstarke und elegante Funktion in Python, mit der Sie Funktionen und Klassen auf saubere und deklarative Weise verbessern können.
Wenn Sie die Prinzipien, Best Practices und potenziellen Fallstricke verstehen, können Sie Dekoratoren effektiv nutzen, um modulareren, wartbareren und aussagekräftigeren Code zu schreiben.
Sie sind ein wertvolles Werkzeug im Arsenal jedes Python-Programmierers, insbesondere wenn er mit Frameworks arbeitet oder wiederverwendbare Komponenten erstellt.
Das obige ist der detaillierte Inhalt vonPython-Dekoratoren: Ein umfassender Leitfaden. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen

So verwenden Sie Python, um die ZiPF -Verteilung einer Textdatei zu finden

So herunterladen Sie Dateien in Python

Wie benutze ich eine schöne Suppe, um HTML zu analysieren?

Wie man mit PDF -Dokumenten mit Python arbeitet

Wie kann man mit Redis in Django -Anwendungen zwischenstrichen

Einführung des natürlichen Sprach -Toolkits (NLTK)

Wie führe ich ein tiefes Lernen mit Tensorflow oder Pytorch durch?
