Side-by-Side Language Deep Dive

Decoradores de Python versus patrón de diseño decorador: las diferencias clave

Compare los decoradores de Python y el patrón de diseño de decorador clásico. Comprenda las diferencias entre el ajuste de funciones en tiempo de definición y la composición dinámica de objetos en tiempo de ejecución con código ejecutable.

Si bien los decoradores de Python y el patrón de diseño del decorador comparten el mismo nombre y el mismo concepto general de "ajustar" el código para extender el comportamiento, representan construcciones y filosofías de programación completamente diferentes.

Un decorador de Python es una característica del lenguaje: azúcar sintáctico que le permite envolver una función, método o clase en el momento de la definición. Es una forma de metaprogramación que se ejecuta cuando se importa o define el módulo, cambiando el comportamiento de esa función durante el resto de la ejecución de la aplicación.

El patrón de diseño decorador, originalmente definido por la Banda de los Cuatro (GoF), es un patrón de diseño estructural orientado a objetos. Está diseñado para agregar responsabilidades a objetos individuales dinámicamente en tiempo de ejecución, sin afectar a otros objetos de la misma clase, mediante el uso de clases contenedoras y composición dinámica.

Matriz de comparación de características

FeaturePythonOther Language
Concepto centralAzúcar sintáctico a nivel de lenguaje para envolver funciones/clases.Patrón de diseño para agregar dinámicamente comportamiento a objetos individuales.
Tiempo de ejecuciónTiempo de definición (se ejecuta una vez cuando se carga el módulo).Tiempo de ejecución (instanciado dinámicamente durante la ejecución del programa).
Entidad objetivoFunciones, métodos o clases completas (alcance estático).Instancias de objetos específicos (alcance dinámico).
Método de implementaciónCierres y funciones auxiliares que utilizan la sintaxis `@decorator`.Herencia de clases, alineación de interfaces y composición de objetos.

Syntax & Idiom Comparisons

01.Decorador de Python: contenedor de funciones (tiempo de definición)

Los decoradores de Python aprovechan funciones de primera clase para interceptar llamadas. Cuando escribe `@my_decorator`, Python pasa la función decorada a su función decoradora y vincula la función contenedora devuelta al nombre de la función original.

En este ejemplo, el decorador `@log_call` envuelve una función simple para rastrear cuándo se ejecuta y qué devuelve. Tenga en cuenta que esta envoltura está escrita en piedra en el momento en que se define la función.

def log_call(func):
    def wrapper(*args, **kwargs):
        print(f"[LOG] Executing '{func.__name__}' with args {args}")
        result = func(*args, **kwargs)
        print(f"[LOG] '{func.__name__}' returned: {result}")
        return result
    return wrapper

@log_call
def add(a, b):
    return a + b

# The wrapping occurs once at definition time
print("Result of add(5, 7):", add(5, 7))
python
// Decorators in Python are syntactic sugar for function wrappers:
// add = log_call(add)
// They exist primarily to avoid duplicate boilerplate for logging, timing, and auth.

02.Patrón de diseño decorador: contenedor de objetos (composición en tiempo de ejecución)

El patrón de diseño decorador clásico utiliza composición de clases. Tiene una clase de componente base y clases decoradoras que envuelven este componente base. En tiempo de ejecución, encadena estos constructores para crear un objeto personalizado de forma dinámica.

Aquí implementamos un sistema clásico de decoración de café. Podemos envolver un objeto Coffee básico dentro de un MilkDecorator y envolverlo dentro de un SugarDecorator, calculando el costo final dinámicamente en tiempo de ejecución.

class Coffee:
    def get_cost(self):
        return 5.0
    def get_description(self):
        return "Simple Coffee"

class MilkDecorator:
    def __init__(self, coffee):
        self.coffee = coffee
    def get_cost(self):
        return self.coffee.get_cost() + 1.5
    def get_description(self):
        return self.coffee.get_description() + ", Milk"

class SugarDecorator:
    def __init__(self, coffee):
        self.coffee = coffee
    def get_cost(self):
        return self.coffee.get_cost() + 0.5
    def get_description(self):
        return self.coffee.get_description() + ", Sugar"

# Chaining wrappers dynamically at runtime
my_drink = Coffee()
my_drink = MilkDecorator(my_drink)
my_drink = SugarDecorator(my_drink)

print("Drink description:", my_drink.get_description())
print("Total Cost: $", my_drink.get_cost())
python
// Standard OO languages (like Java) require shared interfaces:
// interface Coffee { double getCost(); }
// class SimpleCoffee implements Coffee { ... }
// class MilkDecorator implements Coffee { ... }
// Python's duck typing allows dynamic composition without interfaces.

Veredicto y resumen

Utilice decoradores de Python (@decorator) cuando desee aplicar cuestiones transversales (como registro, temporización, autenticación, almacenamiento en caché o validación de entradas) a funciones o rutas de manera uniforme en toda su aplicación.

Utilice el patrón de diseño Decorator cuando necesite adjuntar o separar comportamientos de instancias de objetos individuales dinámicamente en tiempo de ejecución, especialmente cuando combine múltiples clases contenedoras opcionales en secuencias arbitrarias.

Preguntas frecuentes

¿Por qué la página de Wikipedia dice que los decoradores de Python no son el patrón decorador?

Porque los decoradores estándar de Python envuelven funciones y definiciones de clases en el momento de la compilación/definición, lo que afecta a todas las instancias de esa función. El patrón de diseño clásico envuelve instancias de objetos individuales dinámicamente en tiempo de ejecución.

¿Es útil el patrón decorador GoF en Python?

Sí, pero la escritura pato de Python hace que sea mucho más sencillo de implementar que en lenguajes de tipado estático como Java o C++, ya que los decoradores no necesitan heredar de una interfaz base formal.

Otras comparaciones

Recursos recomendados de Python

Amplíe sus conocimientos con tutoriales interactivos relacionados, hojas de trucos y comparaciones de códigos.