Python-Dekoratoren

Ein Dekorator ist ein fortgeschrittenes Merkmal in Python, mit demdie Funktionalität von Funktionen oder Klassen dynamisch erweitert werden kann, ohne den ursprünglichen Funktionscode zu ändern。

Im Wesentlichen ist ein Dekorator eine Funktion: Er erhält eine Funktion als Argument und gibt eine neue Funktion zurück (normalerweise eine erweiterte Version der ursprünglichen Funktion).

Dekoratoren werden mit der@decorator_name-Syntax vor einer Funktions- oder Methodendefinition verwendet.

Python bietet auch einige integrierte Dekoratoren, wie z. B.@staticmethodund@classmethod。

Häufige Anwendungsfälle:

  • Protokollierung:Funktionsaufrufinformationen, Parameter und Rückgabewerte aufzeichnen
  • Leistungsstatistiken:Ausführungszeit der Funktion messen
  • Zugriffskontrolle:Zugriffsberechtigungen für Funktionen einschränken
  • Caching:Funktionsergebnisse zwischenspeichern, um die Leistung zu verbessern

Grundlegende Syntax

Die Kernidee eines Dekorators ist:eine Funktion zu verwenden, um eine andere Funktion zu "umschließen"。

Syntax

def decorator_function(original_function):
    def wrapper(*args, **kwargs):
        # Vor dem Aufruf
        print("Vor der Ausführung")

        result = original_function(*args, **kwargs)

        # Nach dem Aufruf
        print("Nach der Ausführung")

        return result
    return wrapper

@decorator_function
def target_function():
    print("Ausführung der Originalfunktion")

Erklärung:

  • decorator_function: Dekorator-Funktion (empfängt die Originalfunktion)
  • wrapper: Wrapper-Funktion (wird tatsächlich ausgeführt)
  • @decorator_function: entspricht dem Ersetzen einer Funktion

Äquivalente Form:

target_function = decorator_function(target_function)

👉 Beim Aufruftarget_function(), was tatsächlich ausgeführt wird, istwrapper()


Dekoratoren verwenden

Dekoratoren werden mit dem@syntaktischen Zucker angewendet, der vor der Funktionsdefinition platziert wird:

@time_logger
def target_function():
    pass

Entspricht:

def target_function():
    pass

target_function = time_logger(target_function)

Dieser Mechanismus ermöglicht es uns, Funktionalität (wie Protokollierung, Berechtigungen usw.) einheitlich hinzuzufügen, ohne die ursprüngliche Funktion zu ändern.


Beispiel: Logs ausgeben

def my_decorator(func):
    def wrapper():
        print("Vor der Funktionsausführung")
        func()
        print("Nach der Funktionsausführung")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

Ausgabe:

函数执行前
Hello!
函数执行后
  • my_decoratorEmpfängtsay_hello
  • @my_decoratorErsetzt die ursprüngliche Funktion

Dekoratoren mit Parametern

Wenn die ursprüngliche Funktion Parameter hat, müssen Sie in derwrapperVerwenden Sie*args, **kwargs:

Beispiel

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Vor der Ausführung")
        func(*args, **kwargs)
        print("Nach der Ausführung")
    return wrapper

@my_decorator
def greet(name):
    print(f"Hallo, {name}!")

greet("Alice")

Ausgabe:

执行前
Hello, Alice!
执行后

Erklärung:Verwenden*args, **kwargskann Funktionen mit beliebig vielen Parametern aufnehmen.


Dekoratoren mit Parametern (Fortgeschritten)

def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def say_hello():
    print("Hello!")

say_hello()

Erklärung:Dies ist eine "Dekorator-Fabrik"; die äußere Funktion dient zum Empfangen von Parametern.

Hello!
Hello!
Hello!


Klassendekoratoren

Zusätzlich zu Funktionen können Dekoratoren auch auf Klassen angewendet werden.

Ein Klassendekorator empfängt eine Klasse und gibt eine modifizierte Klasse oder eine Wrapper-Klasse zurück.

  • Klassenmethoden erweitern
  • Den Instanziierungsprozess steuern
  • Funktionalität wie Singletons und Logging implementieren

Funktionsbasierte Klassendekoratoren

Beispiel

def log_class(cls):
    class Wrapper:
        def __init__(self, *args, **kwargs):
            self.wrapped = cls(*args, **kwargs)

        def __getattr__(self, name):
            return getattr(self.wrapped, name)

        def display(self):
            print("Vor dem Aufruf")
            self.wrapped.display()
            print("Nach dem Aufruf")

    return Wrapper

@log_class
class MyClass:
    def display(self):
        print("Ursprüngliche Methode")

obj = MyClass()
obj.display()
Before call
Original method
After call

Klassenbasierte Klassendekoratoren

Beispiel: Singleton-Muster

class SingletonDecorator:
    def __init__(self, cls):
        self.cls = cls
        self.instance = None

    def __call__(self, *args, **kwargs):
        if self.instance is None:
            self.instance = self.cls(*args, **kwargs)
        return self.instance

@SingletonDecorator
class Database:
    def __init__(self):
        print("Initialisierung")

db1 = Database()
db2 = Database()
print(db1 is db2)
初始化
True

Eingebaute Dekoratoren

Häufig verwendete eingebaute Dekoratoren:

  1. @staticmethod: definiert eine statische Methode
  2. @classmethod: definiert eine Klassenmethode
  3. @property: verwandelt eine Methode in eine Eigenschaft

Beispiel

class MyClass:
    @staticmethod
    def static_method():
        print("Static method")

    @classmethod
    def class_method(cls):
        print(cls.__name__)

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

Mehrere Decorators stapeln

Mehrere Decoratorsumhüllen die Funktion während der Definitionsphase von unten nach oben,und werden während der Aufrufphase von oben nach unten ausgeführt:

Beispiel

def decorator1(func):
    def wrapper():
        print("Decorator 1")
        func()
    return wrapper

def decorator2(func):
    def wrapper():
        print("Decorator 2")
        func()
    return wrapper

@decorator1
@decorator2
def say_hello():
    print("Hello!")

say_hello()

Endgültige Ausgabe:

Decorator 1
Decorator 2
Hello!

Kernzusammenfassung

Decorator = a function that wraps a function + extending functionality without modifying the original code
  • Die @-Syntax ist im Wesentlichen ein Funktionsersatz
  • wrapper ist die Funktion, die tatsächlich ausgeführt wird
  • Es wird empfohlen, *args, **kwargs für größere Vielseitigkeit zu verwenden
  • Unterstützt Funktionen, Klassen und sogar Dekoratoren mit Parametern
Andere Erweiterungen