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.
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:
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.
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.
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:
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:
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)
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!"
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
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
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))
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:
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:
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")
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.
Eine kuratierte Liste von Python-Dekoratoren finden Sie unten:
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!