Puedes ejecutar cualquier ejemplo en nuestra consola interactiva: Abrir consola de Python →
Decoradores avanzados en Python
Los decoradores permiten modificar el comportamiento de funciones y métodos sin alterar su código interno. En esta guía aprenderás técnicas avanzadas como decoradores con argumentos, stacking, preservación de metadatos, decoradores para clases y patrones profesionales usados en proyectos reales.
Tabla de contenidos
- Decoradores con argumentos
- Decoradores anidados (stacking)
- functools.wraps
- Decoradores para métodos
- Decoradores para clases
- Decoradores parametrizados profesionales
- Ejercicios
- Mini‑proyecto
1. Decoradores con argumentos
Un decorador puede recibir parámetros si se encapsula en una función externa.
def repetir(n):
def decorador(func):
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorador
@repetir(3)
def saludar():
print("Hola")
saludar()
2. Decoradores anidados (stacking)
Puedes aplicar varios decoradores a una misma función.
def mayus(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs).upper()
return wrapper
def exclamacion(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs) + "!"
return wrapper
@mayus
@exclamacion
def mensaje():
return "hola"
print(mensaje())
3. functools.wraps
wraps preserva el nombre y docstring de la función original.
from functools import wraps
def log(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Ejecutando:", func.__name__)
return func(*args, **kwargs)
return wrapper
@log
def sumar(a, b):
"""Suma dos números."""
return a + b
print(sumar.__name__)
print(sumar.__doc__)
4. Decoradores para métodos
def verificar_login(func):
def wrapper(self, *args, **kwargs):
if not self.logueado:
raise PermissionError("Usuario no logueado")
return func(self, *args, **kwargs)
return wrapper
class Usuario:
def __init__(self):
self.logueado = False
@verificar_login
def acceder(self):
return "Acceso permitido"
5. Decoradores para clases
Un decorador puede modificar o extender una clase completa.
def agregar_repr(cls):
def __repr__(self):
return f"{cls.__name__}({self.__dict__})"
cls.__repr__ = __repr__
return cls
@agregar_repr
class Punto:
def __init__(self, x, y):
self.x = x
self.y = y
print(Punto(3, 4))
6. Decoradores parametrizados profesionales
def validar_tipo(tipo):
def decorador(func):
def wrapper(valor):
if not isinstance(valor, tipo):
raise TypeError("Tipo incorrecto")
return func(valor)
return wrapper
return decorador
@validar_tipo(int)
def cuadrado(n):
return n * n
7. Ejercicios
- Crea un decorador que mida el tiempo de ejecución.
- Crea un decorador que cache resultados.
- Crea un decorador para validar rangos numéricos.
- Crea un decorador para registrar llamadas en un archivo.
- Crea un decorador que convierta la salida a JSON.
import time
def medir(func):
def wrapper(*a, **kw):
ini = time.time()
r = func(*a, **kw)
print(time.time() - ini)
return r
return wrapper
cache = {}
def memo(func):
def wrapper(x):
if x not in cache:
cache[x] = func(x)
return cache[x]
return wrapper
def rango(mini, maxi):
def deco(func):
def wrapper(n):
if not mini <= n <= maxi:
raise ValueError("Fuera de rango")
return func(n)
return wrapper
return deco
8. Mini‑proyecto: Sistema de logging avanzado
def logger(nombre):
def decorador(func):
def wrapper(*args, **kwargs):
print(f"[{nombre}] Ejecutando {func.__name__}")
return func(*args, **kwargs)
return wrapper
return decorador
@logger("DB")
def conectar():
return "Conectado"
print(conectar())