Cómo crear y utilizar decoradores en Python

Aprenda a escribir y aplicar decoradores en Python. Domine las funciones de ajuste, modifique el comportamiento, maneje argumentos y preserve metadatos con ajustes.

Pruebe esta solución en el Editor

Descripción general

Los decoradores son una de las características de sintaxis más elegantes y poderosas de Python, que le permiten modificar el comportamiento de una función o clase sin cambiar permanentemente su código. Se utilizan ampliamente para cuestiones transversales como registrar tiempos de ejecución, hacer cumplir la autenticación de usuarios, almacenar en caché los resultados (memorización) y auditar los puntos finales de API.

En esencia, un decorador es una función de orden superior que toma otra función como argumento, define una función contenedora anidada que inyecta cierta lógica personalizada y devuelve esta función contenedora. Python proporciona una sintaxis taquigráfica limpia utilizando el símbolo `@` para aplicar decoradores a funciones, haciéndolas visualmente elegantes.

Al escribir decoradores, normalmente querrá que la función decorada admita cualquier número de argumentos posicionales y de palabras clave. Puede lograr esto diseñando la función contenedora anidada para aceptar `*args` y `**kwargs` y pasarlos a la función de destino. Además, debe usar `functools.wraps` en la función contenedora para preservar la cadena de documentación y los metadatos del nombre de la función original.

Código y salida de ejecución

Este script demuestra cómo escribir un decorador de registro y ajustar una función para inspeccionar entradas, salidas y metadatos.

decorators_tutorial.py
Pruébelo en el editor
from functools import wraps

# 1. Defining a decorator
def log_execution(func):
    @wraps(func) # Preserves original function metadata
    def wrapper(*args, **kwargs):
        print(f"[Log] Calling function: {func.__name__} with args: {args}")
        result = func(*args, **kwargs)
        print(f"[Log] Finished {func.__name__}. Result: {result}")
        return result
    return wrapper

# 2. Applying the decorator using @ syntax
@log_execution
def add_numbers(a, b):
    """Adds two numbers and returns the sum."""
    return a + b

# 3. Invoking the decorated function
sum_result = add_numbers(15, 25)
print("Sum Result:", sum_result)

# Verifying metadata preservation
print("Docstring preserved:", add_numbers.__doc__)
Salida terminal
[Log] Calling function: add_numbers with args: (15, 25)
[Log] Finished add_numbers. Result: 40
Sum Result: 40
Docstring preserved: Adds two numbers and returns the sum.

Implementación paso a paso

  • Defina una función decoradora externa que tome la función de destino como argumento.
  • Importe y aplique @functools.wraps(func) en su función contenedora anidada para proteger los metadatos originales.
  • Implemente wrapper(*args, **kwargs) para capturar variables de entrada, inyectar lógica e invocar la función de destino.
  • Devuelve el objeto de función contenedora del bloque de encabezado decorador.
  • Aplique el decorador usando @decorator_name directamente encima de la firma de la función de destino.

Preguntas frecuentes

¿Por qué es necesario @functools.wraps dentro de los decoradores?

Sin envolturas, la función decorada pierde su identidad original (sus atributos __name__ y __doc__ son reemplazados por los de la función contenedora anidada), lo que dificulta la depuración y la introspección del código.

¿Puedo aplicar varios decoradores a una sola función?

¡Sí! Puede encadenar decoradores apilando varias líneas @. Python los aplica de abajo hacia arriba (la definición de función más cercana se ejecuta primero).

Temas relacionados

Recursos recomendados de Python

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