
Uno de los aspectos más poderosos pero también más confusos de Python para muchos desarrolladores —especialmente quienes vienen de otros lenguajes— son los decoradores. Este artículo busca ayudarte a entender qué son, cómo funcionan y cómo usarlos correctamente en tus propios proyectos.
¿Qué es un decorador en Python?
Un decorador es, en esencia, una función que recibe otra función como argumento y devuelve una nueva función que puede alterar o extender el comportamiento de la original sin modificar su código fuente. Se basa en dos conceptos fundamentales de Python: funciones de orden superior y closures.
¿Por qué usar decoradores?
- Separar la lógica transversal del núcleo de la función (por ejemplo: logging, validación, control de acceso).
- Reutilizar comportamiento en múltiples funciones sin duplicar código.
- Extender funcionalidades en bibliotecas de terceros.
- Aplicar principios de programación funcional de manera más limpia y legible.
El ejemplo más simple de decorador
Vamos a comenzar con un decorador básico que imprime un mensaje antes y después de ejecutar una función.
def mi_decorador(func):
def envoltura():
print("Antes de ejecutar la función")
func()
print("Después de ejecutar la función")
return envoltura
@mi_decorador
def saludar():
print("Hola mundo")
saludar()
El uso de @mi_decorador
es azúcar sintáctica para saludar = mi_decorador(saludar)
.
Decoradores con argumentos
Para que nuestro decorador sea más flexible, podemos permitirle aceptar argumentos.
def decorador_con_argumentos(func):
def envoltura(*args, **kwargs):
print(f"Llamando a {func.__name__} con argumentos: {args}, {kwargs}")
return func(*args, **kwargs)
return envoltura
@decorador_con_argumentos
def sumar(a, b):
return a + b
resultado = sumar(5, 3)
print(f"Resultado: {resultado}")
Decoradores anidados (decoradores con parámetros)
También es posible crear decoradores que reciben sus propios parámetros:
def repetir(n):
def decorador(func):
def envoltura(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return envoltura
return decorador
@repetir(3)
def decir_hola():
print("Hola!")
decir_hola()
En este ejemplo, el decorador repite la ejecución de la función decorada n
veces.
Preservando metadata con functools.wraps
Al decorar una función, esta pierde su metadata como nombre, docstring, etc. Para evitarlo, usamos functools.wraps
:
import functools
def decorador(func):
@functools.wraps(func)
def envoltura(*args, **kwargs):
print("Ejecutando", func.__name__)
return func(*args, **kwargs)
return envoltura
@decorador
def saludar():
"""Esta función saluda"""
print("¡Hola!")
print(saludar.__name__) # 'saludar'
print(saludar.__doc__) # 'Esta función saluda'
Aplicaciones comunes de decoradores
- Medición de tiempo de ejecución
- Memoización y caching
- Control de acceso/autenticación
- Validación de entrada
- Registro de eventos o errores
Ejemplo: medidor de tiempo de ejecución
import time
import functools
def medir_tiempo(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
inicio = time.time()
resultado = func(*args, **kwargs)
fin = time.time()
print(f"{func.__name__} tomó {fin - inicio:.4f} segundos")
return resultado
return wrapper
@medir_tiempo
def tarea_lenta():
time.sleep(1)
print("Tarea completada.")
tarea_lenta()
Decoradores integrados en Python
Python ofrece varios decoradores ya integrados en el lenguaje:
@staticmethod
: convierte un método en un método estático.@classmethod
: permite que un método reciba la clase como primer argumento.@property
: convierte un método en un atributo de solo lectura.
Decoradores en frameworks populares
Los decoradores son usados ampliamente en frameworks de Python. Algunos ejemplos:
- Flask:
@app.route()
para definir rutas. - Django:
@login_required
para proteger vistas. - Pytest:
@pytest.mark.parametrize
para pruebas con múltiples valores.
Errores comunes al usar decoradores
- Olvidar retornar la función interna (envoltura).
- No usar
functools.wraps
, perdiendo metadata útil. - Confundir decoradores con o sin argumentos.
- No manejar bien los argumentos y kwargs en la envoltura.
Conclusión
Los decoradores son una herramienta poderosa en Python que te permiten escribir código más limpio, reutilizable y expresivo. Aunque su sintaxis pueda parecer compleja al principio, con práctica se vuelven una parte natural del desarrollo Python moderno. Desde bibliotecas populares hasta utilidades personalizadas, dominarlos te hará un desarrollador más competente y versátil.
Te animo a que pruebes escribir tus propios decoradores en distintos contextos. La práctica es la clave para interiorizar este patrón.
Publicar un comentario