ProgramaciónDesarrollador Backend

¿Qué son los decoradores de funciones de orden superior en Python, cómo permiten implementar el patrón de 'envoltura' y qué se debe tener en cuenta al trabajar con metadatos/documentación de funciones?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

En Python, un decorador de función de orden superior es una función que toma otra función (o clase) y devuelve una nueva función (o una clase modificada). Los decoradores se utilizan a menudo para implementar el patrón de "envoltura" (wrapping), que permite agregar lógica adicional (por ejemplo, registro, caché, verificación de permisos, etc.) a funciones existentes sin modificar su código fuente.

Para preservar el nombre, la documentación y otros metadatos de la función original, se recomienda utilizar la función functools.wraps:

import functools def log_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print(f'Calling {func.__name__}') return func(*args, **kwargs) return wrapper @log_decorator def add(a, b): """Suma dos números""" return a + b print(add(2, 3)) # Salida: Calling add 5 print(add.__name__) # Salida: add print(add.__doc__) # Salida: Suma dos números

Punto clave: sin functools.wraps, la función envuelta perderá su nombre, documentación y otros metadatos del original, lo que afecta negativamente a la depuración y la autodocumentación.

Pregunta con trampa.

Si decoras una función sin usar functools.wraps, ¿qué pasará con los atributos name y doc de la función?

Respuesta: Serán heredados de la función interna envoltora (normalmente 'wrapper'), y perderás los metadatos originales.

def simple_decorator(func): def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper @simple_decorator def f(): """Esta es la cadena de documentación""" pass print(f.__name__) # Salida: 'wrapper' (NO 'f') print(f.__doc__) # Salida: None (no 'Esta es la cadena de documentación')

Ejemplos de errores reales debido a la falta de conocimiento sobre los detalles del tema.


Historia

En el proyecto se implementó un sistema complejo de decoradores para registrar los endpoints de la API, pero no se aplicó functools.wraps. Como resultado, la autogeneración de documentación (Swagger/OpenAPI) y las herramientas de introspección mostraban los nombres de todos los endpoints como 'wrapper', y la documentación desapareció. Esto dificultó seriamente el mantenimiento, las pruebas y el soporte.


Historia

Al escribir pruebas unitarias con pytest, falló la auto-descubrimiento de pruebas: las funciones de prueba decoradas con sus decoradores sin wraps no se detectaron porque su name era incorrecto. La razón es que pytest busca funciones por nombre.


Historia

Al rastrear la pila de excepciones (traceback), la pila de llamadas siempre apuntaba a 'wrapper', y era imposible entender qué función había causado el error, dado que los metadatos raíz se perdieron por la falta de functools.wraps en los decoradores personalizados.