Un decorador de clase es una función que toma una clase como argumento y devuelve una clase modificada o completamente nueva. Con ellos, se pueden agregar dinámicamente métodos, cambiar el comportamiento de métodos existentes o incluso devolver una subclase que amplíe la funcionalidad de la clase original.
def add_repr(cls): def __repr__(self): return f'<{cls.__name__}: {self.__dict__}>' cls.__repr__ = __repr__ return cls @add_repr class Point: def __init__(self, x, y): self.x = x self.y = y p = Point(3, 4) print(p) # <Point: {'x': 3, 'y': 4}>
add_repr agrega dinámicamente el método __repr__ a todas las clases a las que se aplica.*args y **kwargs, que se utilizan al crear instancias de la clase.¿Qué ocurrirá si se aplican dos decoradores de clase uno tras otro? ¿Siempre es obvio el orden de su aplicación?
Los decoradores se aplican "de abajo hacia arriba": primero se aplica el decorador que está directamente sobre la declaración de la clase, luego el siguiente más arriba, etc. El orden es MUY IMPORTANTE, ya que el resultado del primer decorador se pasa al segundo y así sucesivamente.
@dec1 @dec2 class Test: ... # Equivalente a: # Test = dec1(dec2(Test))
Historia
En una aplicación de e-commerce, se quería registrar los métodos de la clase, pero accidentalmente se devolvió el objeto incorrecto desde el decorador, y los métodos perdieron su atributo de clase, lo que rompió la herencia y causó fallos en el modelo.
Historia
En un proyecto para la autogeneración de nuevos métodos, se utilizó un decorador adicional, pero se olvidó llamar a super() al devolver la subclase. Esto resultó en una violación de la jerarquía y del MRO, causando que las llamadas al clase base en las derivadas no funcionaran.
Historia
En un data pipeline, se intentó envolver las clases con varios decoradores (registrador, rastreador de cambios), pero debido a un orden incorrecto de aplicación, se produjo un conflicto de nombres de métodos, lo que llevó a errores en producción debido a métodos "perdidos".