Dominando Decoradores en Python: Mejora Funciones con Técnicas Expertas
Decoradores en Python
Los decoradores te permiten envolver funciones con lógica reutilizable, haciendo tu código más modular, legible y mantenible. En esta guía construimos, explicamos y aplicamos decoradores en escenarios reales.
Video: @Decoradores en Python
Decoradores en Python
Los decoradores de Python son una poderosa herramienta de metaprogramación que permite añadir comportamiento a funciones o clases en tiempo de definición. Como todo en Python es un objeto —incluyendo funciones y clases— los decoradores operan tomando un callable, envolviéndolo en otro, y devolviendo el nuevo callable.
Prerrequisitos para Aprender Decoradores
Antes de sumergirte, debes estar cómodo con el hecho de que en Python, las funciones son objetos de primera clase. Los nombres son simplemente referencias vinculadas a objetos; la misma función puede ser referenciada por múltiples nombres.
def first(msg):
print(msg)
first("Hola")
second = first
second("Hola")
Salida
Hola Hola
Las funciones pueden pasarse como argumentos, retornarse desde otras funciones, e incluso anidarse dentro de otras funciones. Estos conceptos —funciones de orden superior, funciones anidadas y closures— son los bloques de construcción de los decoradores.
def inc(x):
return x + 1
def dec(x):
return x - 1
def operate(func, x):
result = func(x)
return result
Uso:
>>> operate(inc, 3)
4
>>> operate(dec, 3)
2
def is_called():
def is_returned():
print("Hola")
return is_returned
new = is_called()
new()
Salida
Hola
Entender closures es clave: la función anidada retiene acceso al ámbito envolvente, que es precisamente lo que los decoradores explotan para almacenar metadatos o modificar comportamiento.
Volviendo a los Decoradores
En Python, un decorador es simplemente un callable que acepta una función (u otro callable) y devuelve un nuevo callable. Esta función retornada típicamente envuelve la original, añadiendo o alterando funcionalidad antes o después de la llamada.
def make_pretty(func):
def inner():
print("Me decoraron")
func()
return inner
def ordinary():
print("Soy ordinaria")
Ejemplo de uso:
>>> ordinary()
Soy ordinaria
>>> pretty = make_pretty(ordinary)
>>> pretty()
Me decoraron
Soy ordinaria
El patrón decorador mantiene la semántica de la función original intacta mientras la aumenta. Para evitar reasignación manual, Python proporciona azúcar sintáctica con el símbolo @:
@make_pretty
def ordinary():
print("Soy ordinaria")
Esto es equivalente a:
def ordinary():
print("Soy ordinaria")
ordinary = make_pretty(ordinary)
Decorando Funciones con Parámetros
Muchos decoradores deben manejar argumentos arbitrarios. La sintaxis *args y **kwargs permite capturar cualquier argumento posicional o por palabra clave y reenviarlos sin cambios.
def works_for_all(func):
def inner(*args, **kwargs):
print("Puedo decorar cualquier función")
return func(*args, **kwargs)
return inner
Manejar casos edge es otro caso de uso común de decoradores. Por ejemplo, proteger contra división por cero:
def smart_divide(func):
def inner(a, b):
print("Voy a dividir", a, "y", b)
if b == 0:
print("¡Ups! no se puede dividir")
return
return func(a, b)
return inner
@smart_divide
def divide(a, b):
print(a/b)
Uso:
>>> divide(2, 5)
Voy a dividir 2 y 5
0.4
>>> divide(2, 0)
Voy a dividir 2 y 0
¡Ups! no se puede dividir
Encadenando Decoradores en Python
Los decoradores pueden apilarse. El orden de aplicación importa, ya que cada decorador recibe la función retornada por el de abajo.
def star(func):
def inner(*args, **kwargs):
print("*" * 30)
func(*args, **kwargs)
print("*" * 30)
return inner
def percent(func):
def inner(*args, **kwargs):
print("%" * 30)
func(*args, **kwargs)
print("%" * 30)
return inner
@star
@percent
def printer(msg):
print(msg)
Resultado:
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Hola %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
Invertir el orden intercambia los patrones circundantes, demostrando cómo el apilamiento de decoradores influye en el comportamiento.
python
- Dominando tipos de datos en Python: Guía práctica
- Dominando operadores en Python: Guía completa
- Dominando la sentencia pass en Python: Guía práctica
- Dominando argumentos de funciones en Python: Posicionales, por palabra clave y por defecto
- Funciones lambda en Python: Guía práctica de funciones anónimas
- Dominando las funciones lambda en Python: ejemplos prácticos y mejores prácticas
- Función abs() en Python: calcular valores absolutos para números y complejos
- Función round() en Python explicada con ejemplos prácticos
- Dominando la función range() de Python: desde lo básico a casos avanzados
- Dominando la función map() de Python: sintaxis, ejemplos y mejores prácticas
- Dominando yield en Python: Generadores vs Return – Guía práctica