En Python una función puede guardarse en una variable, pasarse como argumento y devolverse como resultado. Un decorador aprovecha exactamente eso para construir una versión modificada de otra función.
La sintaxis @algo es cómoda, pero no es el concepto. Primero entenderás la transformación; después usarás la abreviatura.
Seguir la transformación función original → decorador → función envuelta sin depender de la sintaxis @.
Antes de decorar, observa una función que transforma otra función
def hacer_entusiasta(funcion):
def nueva_funcion():
return funcion() + "!"
return nueva_funcion
def saludo():
return "Hola"
saludo = hacer_entusiasta(saludo)
print(saludo())hacer_entusiasta recibe la función original y devuelve nueva_funcion. A partir de la reasignación, el nombre saludo apunta a la versión envuelta.
La sintaxis @ expresa la misma transformación junto a la definición
def hacer_entusiasta(funcion):
def nueva_funcion():
return funcion() + "!"
return nueva_funcion
@hacer_entusiasta
def saludo():
return "Hola"
print(saludo())Conceptualmente, @hacer_entusiasta equivale a aplicar saludo = hacer_entusiasta(saludo) después de definir la función.
Si esto todavía cuesta: ignora temporalmente la @ y vuelve a escribir mentalmente la reasignación. Esa traducción es suficiente para seguir.
Un wrapper útil conserva la llamada y añade algo alrededor
Muchos decoradores reales registran llamadas, comprueban permisos, miden tiempo o normalizan resultados. La idea común es que el código adicional vive en un lugar y puede aplicarse a varias funciones.
No empieces intentando construir un decorador que acepte cualquier combinación de argumentos y además otro parámetro de configuración. Primero domina un wrapper pequeño. La generalización vendrá después.
Comprueba el prerrequisito: una función también es un valor
Si escribes otra = saludar sin paréntesis, no ejecutas saludar: guardas la propia función en otro nombre. Un decorador aprovecha exactamente esa capacidad para recibir una función y devolver otra.
@entre_corchetes
def lenguaje():
return "Python"
# equivale conceptualmente a:
lenguaje = entre_corchetes(lenguaje)Completa el wrapper para añadir corchetes alrededor del resultado de la función original. No modifiques lenguaje().
[Python]
La salida aparecerá aquí.
Necesito una pista
- Dentro del wrapper ya puedes llamar a
funcion(). - Construye un string con
[, el resultado y].
Ver una solución razonada
def entre_corchetes(funcion):
def wrapper():
return f"[{funcion()}]"
return wrapper
@entre_corchetes
def lenguaje():
return "Python"
print(lenguaje())Para después: argumentos y decoradores parametrizados
Los wrappers con *args/**kwargs y los decoradores que reciben parámetros añaden otra capa. No los necesitas para reconocer la transformación básica de una función.
Recupera lo anterior · minuto 7
Quieres transformar muchos números uno a uno y aplicar después una función que envuelva el resultado. ¿Qué ideas de este bloque reconoces?
Comprobar
Un generador puede producir valores bajo demanda; una comprehension sirve si quieres materializar una lista; un decorador transforma funciones, no los datos directamente. Elige según el problema, no para usar sintaxis avanzada.
No necesitas dominar decoradores complejos para reconocer uno
- La función original se entrega al decorador.
- El decorador devuelve la función que se usará a partir de entonces.
- La
@es una forma compacta de escribir esa transformación.
si puedes reemplazar mentalmente @registro por mi_funcion = registro(mi_funcion), ya has desmontado la parte que suele parecer “mágica”.