decoradores-en-python

Qué son y cómo usar los decoradores en Python

En Python, un decorador es una función que recibe otra función como argumento y devuelve una nueva función que, generalmente, extiende el comportamiento de la original.

Los decoradores permite modificar o extender el comportamiento de funciones o métodos sin modificar su código fuente.

Se utilizan ampliamente para aspectos transversales como la autenticación, el registro (logging), y la validación, entre otros.

Definir un decorador

Vamos a verlo con un ejemplo

def mi_decorador(func):
    def wrapper():
        print("Algo se hace antes de la función")
        func()
        print("Algo se hace después de la función")
    return wrapper

En este ejemplo

  • mi_decorador es una función que recibe una función func
  • Dentro define una función wrapper (podría tener cualquier nombre)
  • La función wrapper utiliza la función func recibida
  • Finalmente mi_decorador devuelve la función wrapper

Usando un decorador

Ahora, para emplear el decorador se utiliza el símbolo @ seguido del nombre del decorador, antes de la definición de la función que se desea decorar.

@mi_decorador
def saludar():
    print("¡Hola desde LuisLlamas.es!")

saludar()

# Salida:
# Algo se hace antes de la función
# ¡Hola desde LuisLlamas.es!
# Algo se hace después de la función

En este ejemplo:

  • Cuando se invoca a saludar, en realidad mi_decorador “toma el control”
  • mi_decorador recibe la función saludar, y devuelve la función wrapper que la utiliza
  • Esta agrega comportamiento antes y después de la ejecución de saludar

Decoradores con argumentos

Los decoradores también pueden aceptar argumentos. Para hacerlo, se necesita anidar funciones:

  • Una función externa para aceptar los argumentos del decorador
  • Una función interna que acepte la función que será decorada.

Por ejemplo,

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_adios():
    print("Adiós!")

decir_adios()

# Salida:
# Adiós!
# Adiós!
# Adiós!

En este caso,

  • repetir es un decorador que acepta un argumento n
  • Este repite la ejecución de la función decorada n veces

Decoradores en múltiples niveles

Python permite anidar decoradores, aplicando múltiples decoradores a una misma función.

def decorador1(func):
    def envoltura():
        print("Decorador 1 antes")
        func()
        print("Decorador 1 después")
    return envoltura

def decorador2(func):
    def envoltura():
        print("Decorador 2 antes")
        func()
        print("Decorador 2 después")
    return envoltura

@decorador1
@decorador2
def funcion():
    print("Función ejecutándose")

funcion()

# Salida:
# Decorador 1 antes
# Decorador 2 antes
# Función ejecutándose
# Decorador 2 después
# Decorador 1 después

En este ejemplo, funcion está decorada primero por decorador2 y luego por decorador1, mostrando cómo se puede encadenar múltiples decoradores.