Los decoradores son funciones que aceptan otra función y devuelven una nueva función con comportamiento extendido o modificado. Se utilizan a menudo para registro, verificación de permisos, almacenamiento en caché, tiempo de ejecución y más.
Los decoradores se implementan usando cierres (closure) o clases que implementan el método __call__. La sintaxis clásica es:
# Decorador simple def simple_decorator(func): def wrapper(*args, **kwargs): print("Antes de llamar a la función") result = func(*args, **kwargs) print("Después de llamar a la función") return result return wrapper @simple_decorator def my_func(): print("Función principal") my_func()
Como resultado se ejecutará así:
Antes de llamar a la función
Función principal
Después de llamar a la función
La principal utilidad es la encapsulación de la lógica repetitiva fuera de la lógica comercial principal.
Detalles:
functools.wraps, se pierde el nombre de la función original y su docstring.Pregunta: "Si decoro una función con un decorador y luego intento obtener el nombre de la función a través de __name__, ¿qué veré y cómo puedo conservar el nombre original?"
Respuesta:
Por defecto, el nombre cambiará al nombre de la envoltura (generalmente wrapper). Para conservar los metadatos originales, usa functools.wraps:
import functools def dec(f): @functools.wraps(f) def wrapper(*args): return f(*args) return wrapper @dec def foo(): pass print(foo.__name__) # imprimirá 'foo', no 'wrapper'
Historia
En una gran automatización de recursos, después de envolver funciones con decoradores, el sistema de pruebas automáticas, que usaba reflexión sobre los nombres de las funciones de prueba, se rompió. El problema fue la falta de functools.wraps.
Historia
El decorador que añadía registro no soportaba funciones con diferentes firmas, ya que no se usaban *args, **kwargs. Algunas funciones simplemente fallaban en silencio.
Historia
En un proyecto con autorización en la API REST, un desarrollador implementó un decorador con parámetros, pero se olvidó de anidar correctamente las funciones (había anidación de dos niveles en lugar de tres). Como resultado, el decorador no podía aceptar parámetros.