Decoradores Personalizados en Clases-2
Decoradores Personalizados en Clases: Los Asistentes Mágicos 🎩✨
Imagina que tienes un equipo de desarrollo y quieres agregar superpoderes a tus métodos o clases sin modificar su código interno.
¿Qué es un decorador personalizado?
Es una función que modifica o extiende el comportamiento de otra función o clase. En clases, puedes decorar métodos o la clase completa.
Analogía del Equipo de Desarrollo 👨💻
# Nuestros "asistentes mágicos" (decoradores)
def supervisor(func):
"""Verifica que todo esté en orden antes de ejecutar"""
def asistente(*args, **kwargs):
print("🔍 Supervisor: Verificando permisos...")
resultado = func(*args, **kwargs)
print("✅ Supervisor: Tarea completada con éxito")
return resultado
return asistente
def logger(func):
"""Registra todas las actividades"""
def asistente(*args, **kwargs):
print(f"📝 Logger: Ejecutando {func.__name__}")
resultado = func(*args, **kwargs)
print(f"📝 Logger: {func.__name__} completado")
return resultado
return asistente
def medir_tiempo(func):
"""Mide cuánto tiempo toma una tarea"""
import time
def asistente(*args, **kwargs):
inicio = time.time()
resultado = func(*args, **kwargs)
fin = time.time()
print(f"⏱️ Tiempo: {func.__name__} tomó {fin-inicio:.2f} segundos")
return resultado
return asistenteDecoradores en Métodos de Clase
class Desarrollador:
def __init__(self, nombre):
self.nombre = nombre
@supervisor
@logger
def programar(self, proyecto):
print(f"{self.nombre} está programando {proyecto}")
return f"Código de {proyecto} listo"
@medir_tiempo
def probar_codigo(self, modulo):
import time
print(f"{self.nombre} probando {modulo}...")
time.sleep(2) # Simular trabajo pesado
return f"{modulo} probado exitosamente"
# Uso
dev = Desarrollador("Ana")
print("=== PROGRAMAR ===")
resultado1 = dev.programar("Sistema de Pagos")
print(f"Resultado: {resultado1}")
print("\n=== PROBAR CÓDIGO ===")
resultado2 = dev.probar_codigo("Módulo de Usuarios")
print(f"Resultado: {resultado2}")Salida:
=== PROGRAMAR ===
🔍 Supervisor: Verificando permisos...
📝 Logger: Ejecutando programar
Ana está programando Sistema de Pagos
📝 Logger: programar completado
✅ Supervisor: Tarea completada con éxito
Resultado: Código de Sistema de Pagos listo
=== PROBAR CÓDIGO ===
Ana probando Módulo de Usuarios...
⏱️ Tiempo: probar_codigo tomó 2.00 segundos
Resultado: Módulo de Usuarios probado exitosamenteDecoradores que Reciben Parámetros
def repetir(veces):
"""Decorador con parámetros - repite una tarea"""
def decorador_real(func):
def asistente(*args, **kwargs):
resultados = []
for i in range(veces):
print(f"🔄 Repetición {i+1}/{veces}")
resultado = func(*args, **kwargs)
resultados.append(resultado)
return resultados
return asistente
return decorador_real
def validar_entero(posicion):
"""Valida que un parámetro específico sea entero"""
def decorador_real(func):
def asistente(*args, **kwargs):
# args[0] es self, args[posicion] es el parámetro a validar
if posicion < len(args) and not isinstance(args[posicion], int):
raise ValueError(f"El parámetro en posición {posicion} debe ser entero")
return func(*args, **kwargs)
return asistente
return decorador_real
class Calculadora:
@repetir(3)
def saludar(self):
return "¡Hola desde la calculadora!"
@validar_entero(1) # Valida que el primer parámetro (después de self) sea entero
def multiplicar(self, a, b):
return a * b
# Uso
calc = Calculadora()
print("=== REPETIR ===")
resultados = calc.saludar()
print(f"Resultados: {resultados}")
print("\n=== VALIDAR ===")
try:
resultado = calc.multiplicar(5, 3)
print(f"5 * 3 = {resultado}")
calc.multiplicar(5, "no_es_numero") # Esto fallará
except ValueError as e:
print(f"❌ Error: {e}")Decoradores de Clase Completa
def agregar_metodos_extra(cls):
"""Decora una clase completa agregando métodos nuevos"""
class NuevaClase(cls):
def metodo_nuevo(self):
return f"Soy un método nuevo agregado a {cls.__name__}"
def estadisticas(self):
return f"Clase: {cls.__name__}, Métodos: {len(dir(self))}"
return NuevaClase
def conectar_base_datos(cls):
"""Simula conexión a base de datos para la clase"""
cls.base_datos_conectada = True
cls.ultima_conexion = "2024-01-01 10:00:00"
def conectar(self):
return f"{cls.__name__} conectada a BD"
cls.conectar = conectar
return cls
@agregar_metodos_extra
@conectar_base_datos
class Usuario:
def __init__(self, nombre):
self.nombre = nombre
def presentarse(self):
return f"Soy {self.nombre}"
# Uso
usuario = Usuario("Carlos")
print(usuario.presentarse()) # Método original
print(usuario.metodo_nuevo()) # Método agregado por decorador
print(usuario.estadisticas()) # Método agregado por decorador
print(usuario.conectar()) # Método agregado por decorador
print(f"BD conectada: {usuario.base_datos_conectada}")Decoradores Útiles del Mundo Real
import functools
def cache_resultados(func):
"""Almacena resultados para no recalcular"""
cache = {}
@functools.wraps(func)
def wrapper(*args, **kwargs):
clave = str(args) + str(kwargs)
if clave not in cache:
cache[clave] = func(*args, **kwargs)
else:
print("♻️ Usando resultado en caché")
return cache[clave]
return wrapper
def requiere_autenticacion(func):
"""Verifica que el usuario esté autenticado"""
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
if not hasattr(self, 'autenticado') or not self.autenticado:
return "❌ Error: Se requiere autenticación"
return func(self, *args, **kwargs)
return wrapper
class SistemaBanco:
def __init__(self):
self.autenticado = False
def login(self, usuario, contraseña):
if usuario == "admin" and contraseña == "1234":
self.autenticado = True
return "✅ Login exitoso"
return "❌ Login fallido"
@requiere_autenticacion
def ver_saldo(self, cuenta):
return f"💰 Saldo de cuenta {cuenta}: $1000"
@requiere_autenticacion
@cache_resultados
def calcular_interes(self, monto, meses):
print(f"Calculando interés para ${monto} por {meses} meses...")
# Simular cálculo complejo
import time
time.sleep(1)
return monto * (1 + 0.1) ** meses
# Uso
banco = SistemaBanco()
print(banco.ver_saldo("12345")) # ❌ Error: Se requiere autenticación
print(banco.login("admin", "1234")) # ✅ Login exitoso
print(banco.ver_saldo("12345")) # ✅ Ahora funciona
print(banco.calcular_interes(1000, 12)) # Calcula por primera vez
print(banco.calcular_interes(1000, 12)) # ♻️ Usa cachéCreando Tu Propio Ecosistema de Decoradores
class DecoradoresProyecto:
@staticmethod
def validar_email(func):
def wrapper(self, email, *args, **kwargs):
if "@" not in email or "." not in email:
raise ValueError("Email inválido")
return func(self, email, *args, **kwargs)
return wrapper
@staticmethod
def formato_titulo(func):
def wrapper(self, texto, *args, **kwargs):
texto_formateado = texto.title()
return func(self, texto_formateado, *args, **kwargs)
return wrapper
class GestorUsuarios:
@DecoradoresProyecto.validar_email
def crear_usuario(self, email, nombre):
return f"Usuario {nombre} con email {email} creado"
@DecoradoresProyecto.formato_titulo
def crear_post(self, titulo):
return f"Post publicado: {titulo}"
# Uso
gestor = GestorUsuarios()
print(gestor.crear_usuario("ana@example.com", "Ana García"))
print(gestor.crear_post("mi primer post en python"))
try:
gestor.crear_usuario("email_invalido", "Juan")
except ValueError as e:
print(f"Error: {e}")Resumen Mágico 🎩
TUS DECORADORES PERSONALIZADOS = ASISTENTES MÁGICOS
@supervisor → El vigilante que verifica permisos
@logger → El escriba que registra todo
@medir_tiempo → El relojero que cronometra
@repetir → El repetidor que ejecuta múltiples veces
@validar → El guardián que verifica datos
@cache → El memorioso que recuerda resultados
@autenticar → El portero que controla accesosVentajas de los decoradores personalizados:
✅ Reutilización: Un decorador sirve para muchas clases
✅ Mantenibilidad: Cambias en un solo lugar
✅ Legibilidad: El código principal se mantiene limpio
✅ Modularidad: Puedes combinar múltiples decoradores
¡Ahora tienes un equipo de asistentes mágicos para tus clases!
Comentarios
Publicar un comentario