ProgramaciónDesarrollador Backend

¿Qué son los decoradores para métodos de instancia en Python, para qué se usan y cómo se aplican correctamente? Explica el funcionamiento de los decoradores clásicos con ejemplos de funciones y métodos.

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Los decoradores en Python surgieron históricamente como una forma de hacer el código más compacto y legible, encapsulando comportamientos repetidos alrededor de funciones y métodos. Antes de la llegada de la sintaxis @decorator, se aplicaban de manera explícita, lo que complicaba la comprensión del código. Hoy en día, los decoradores juegan un papel clave en la organización de la lógica, verificaciones repetidas, registro, almacenamiento en caché y más.

El problema al trabajar con decoradores radica en manejar correctamente las diferencias entre funciones, métodos de instancia y métodos estáticos/clase. A menudo surgen errores relacionados con la pérdida de información sobre el método, el enlace tardío/temprano de self, así como con la firma de la función (signature).

La solución es que al escribir decoradores universales se debe usar el módulo functools.wraps para conservar los metadatos, y también tener cuidado con el tipo de objeto decorado (por ejemplo, considerar correctamente que los métodos de instancia reciben self como el primer argumento).

Ejemplo de código:

import functools def my_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print(f"Antes de la función: {func.__name__}") result = func(*args, **kwargs) print(f"Después de la función: {func.__name__}") return result return wrapper class Example: @my_decorator def method(self, x): print(f"Método llamado con {x}") ex = Example() ex.method(5)

Características clave:

  • El decorador a nivel de método recibe una función que espera self como el primer argumento.
  • Se recomienda usar functools.wraps para preservar los metadatos originales.
  • Los decoradores se pueden parametrizar para mayor flexibilidad.

Preguntas complicadas.

Si se utiliza un decorador escrito para una función en un método de clase, ¿es obligatorio usar functools.wraps, y qué pasará con self?

No, el decorador en sí funciona, pero sin wraps se pierde el nombre de la función, la asistencia del IDE y la documentación. Self seguirá siendo el primer parámetro, pero la pérdida de metadatos dificultará la depuración y la reflexión.

def bad_decorator(f): def wrapper(*args, **kwargs): print("decorado") return f(*args, **kwargs) return wrapper class Test: @bad_decorator def foo(self): pass print(Test().foo.__name__) # wrapper

¿Se puede aplicar el mismo decorador tanto a un método de instancia como a un método estático?

Sí, pero hay que recordar: los métodos estáticos no reciben self como primer argumento. Si el decorador espera trabajar con self, se generarán errores con @staticmethod / @classmethod.

¿Cómo afecta el decorador a la firma del método y la autocompletación?

En resumen: sin functools.wraps, se pierde la firma y la docstring, lo que provoca que IDEs y muchas herramientas de sugerencia dejen de funcionar correctamente.

Errores comunes y anti-patrones

  • No utilizar functools.wraps — pérdida del nombre de la función, docstring, dificultando la depuración.
  • El decorador está escrito para una función, sin tener en cuenta la existencia de self — no funciona correctamente en los métodos.
  • Reutilización del mismo decorador sin considerar el contexto (método estático/clase/método normal).

Ejemplo de la vida real

Caso negativo: Decoradores sin functools.wraps en todos los métodos de la clase.
Ventajas: prototipo rápido, funciona.
Desventajas: no se pueden buscar errores a través de la pila, el IDE no sugiere la firma.

Caso positivo: Los decoradores utilizan functools.wraps, el código está documentado.
Ventajas: legibilidad, mantenimiento, comodidad en el IDE.
Desventajas: mínima adición a la sintaxis y la atención.