Decoradores de Python

Un decorador es una función avanzada de Python que se utiliza paraampliar dinámicamente la funcionalidad de funciones o clases sin modificar el código de la función original.。

En esencia, un decorador es una función: recibe una función como parámetro y devuelve una nueva función (generalmente una versión mejorada de la función original).

Los decoradores se aplican mediante@decorator_namela sintaxis @ antes de la definición de la función o método.

Python también proporciona algunos decoradores integrados, como@staticmethody@classmethod。

Escenarios de aplicación comunes:

  • Registro de logs:Registrar información de llamadas a funciones, parámetros y valores de retorno.
  • Estadísticas de rendimiento:Calcular el tiempo de ejecución de funciones.
  • Control de permisos:Restringir los permisos de acceso a funciones.
  • Caché:Almacenar en caché los resultados de las funciones para mejorar el rendimiento.

Sintaxis básica

La idea central de los decoradores es:usar una función para 'envolver' a otra función.。

Sintaxis

def decorator_function(original_function):
    def wrapper(*args, **kwargs):
        # Antes de la llamada
        print(Antes de ejecutar)

        result = original_function(*args, **kwargs)

        # Después de la llamada
        print(Después de ejecutar)

        return result
    return wrapper

@decorator_function
def target_function():
    print(Ejecución de la función original)

Análisis:

  • decorator_function: función decoradora (recibe la función original)
  • wrapper: función envolvente (la que realmente se ejecuta)
  • @decorator_function: equivale a reemplazar la función

Escritura equivalente:

target_function = decorator_function(target_function)

👉 Al llamartarget_function(), en realidad se ejecutawrapper()


Usar decoradores

Los decoradores se aplican mediante@el azúcar sintáctico @ antes de la definición de la función:

@time_logger
def target_function():
    pass

Equivale a:

def target_function():
    pass

target_function = time_logger(target_function)

Este mecanismo nos permite agregar funcionalidades de manera uniforme (como registros, permisos, etc.) sin modificar la función original.


Ejemplo: imprimir registros (logs)

def my_decorator(func):
    def wrapper():
        print(Antes de ejecutar la función)
        func()
        print(Después de ejecutar la función)
    return wrapper

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

say_hello()

Salida:

函数执行前
Hello!
函数执行后
  • my_decoratorRecibesay_hello
  • @my_decoratorreemplaza la función original

Decoradores con parámetros

Si la función original tiene parámetros, es necesariowrapperusar *args, **kwargs dentro del wrapper.*args, **kwargs:

Ejemplo

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print(Antes de ejecutar)
        func(*args, **kwargs)
        print(Después de ejecutar)
    return wrapper

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

greet("Alice")

Salida:

执行前
Hello, Alice!
执行后

Explicación:Usar*args, **kwargspuede ser compatible con cualquier función de parámetros.


Decoradores con parámetros (avanzado)

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()

Explicación:Esto es una 'fábrica de decoradores'; la función externa se utiliza para recibir los parámetros.

Hello!
Hello!
Hello!


Decoradores de clase

Además de las funciones, los decoradores también pueden actuar sobre clases.

Un decorador de clase recibe una clase y devuelve la clase modificada o una clase envolvente.

  • Mejorar métodos de clase
  • Controlar el proceso de instanciación
  • Implementar funciones como singleton, registros, etc.

Decorador de clase en forma de función

Ejemplo

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(Antes de la llamada)
            self.wrapped.display()
            print(Después de la llamada)

    return Wrapper

@log_class
class MyClass:
    def display(self):
        print(Método original)

obj = MyClass()
obj.display()
Antes de la llamada
Método original
Después de la llamada

Decorador de clase en forma de clase

Ejemplo: patrón singleton

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(Inicializando)

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

Decoradores integrados

Decoradores integrados comunes:

  1. @staticmethod: define un método estático.
  2. @classmethod: define un método de clase.
  3. @property: convierte un método en una propiedad.

Ejemplo

class MyClass:
    @staticmethod
    def static_method():
        print(Método estático)

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

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

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

Apilamiento de múltiples decoradores

Múltiples decoradores, enla fase de definición, envuelven la función de abajo hacia arriba.,En la fase de llamada, se ejecutan de arriba hacia abajo.:

Ejemplo

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()

Salida final:

Decorator 1
Decorator 2
Hello!

Resumen principal

Decorador = Función que envuelve otra función + Extender funcionalidad sin modificar el código original
  • La sintaxis @ es, en esencia, un reemplazo de función.
  • wrapper es la función que realmente se ejecuta.
  • Se recomienda usar *args, **kwargs para mejorar la versatilidad.
  • Soporta funciones, clases e incluso decoradores con parámetros.
Otras extensiones