Regístrate para acceder a más de 15 cursos gratuitos de programación con un simulador

Decoradores Python: Funciones

En programación, a menudo necesitamos agregar funcionalidad a funciones o clases existentes sin modificar su código original.

Ejemplos comunes incluyen:

  • Registro de logs (guardar información de ejecución).
  • Validación de datos (verificar entradas antes de ejecutar).
  • Medición de tiempo de ejecución (ver cuánto tarda una función).

Python tiene una herramienta poderosa para esto: los decoradores. Veamos cómo funcionan.

¿Qué es un decorador?

Un decorador es una función que envuelve otra función para modificar su comportamiento sin cambiar su código.

Primero, recordemos cómo funcionan los cierres (closures):

def outer(arg1):
    def inner(arg2):
        return arg1 + arg2
    return inner

sumar_dos = outer(2)
sumar_dos(1) # 3
sumar_dos(3) # 5
sumar_dos(5) # 7

La función outer() recibe un número y devuelve otra función que suma ese número a otro. sumar_dos recuerda el valor 2 gracias al closure.

Podemos reescribirlo con lambdas:

def outer(arg1):
    inner = lambda arg2: arg1 + arg2
    return inner

En Python, las funciones son objetos, por lo que pueden manipularse como datos.

Decoradores: funciones que modifican funciones

Podemos aplicar este concepto a funciones:

def outer(func):
    def inner(arg):
        print('Función:', func)
        print('Argumento:', arg)
        return func(arg)
    return inner

def cuadrado(x):
    return x ** 2

envoltura = outer(cuadrado)

envoltura(1) # 1
# => Función: <function cuadrado>
# => Argumento: 1

envoltura(2) # 4
# => Función: <function cuadrado>
# => Argumento: 2

outer() recibe una función y devuelve una nueva función inner() que la ejecuta y agrega mensajes adicionales. No modificamos cuadrado(), solo la envolvemos. Este es el concepto de decoradores.

Uso de decoradores

Supongamos que tenemos esta función para sumar números:

def sumar(*nums):
    resultado = 0
    for num in nums:
        resultado += num
    return resultado

Creamos un decorador para depurar (debugging):

def debug_decorator(func):
    def wrapper(*args, **kwargs):
        print("Args:", args, kwargs)
        resultado = func(*args, **kwargs)
        print("Resultado:", resultado)
        return resultado
    return wrapper

wrapper() no se llama directamente, sino que actúa como una función interna dentro del decorador

Aplicamos el decorador:

sumar = debug_decorator(sumar)

sumar(1, 2, 3) # 6
# => Args: (1, 2, 3) {}
# => Resultado: 6

Ahora, cada vez que llamemos sumar(), se ejecuta con mensajes de depuración.

Sintaxis con @decorador

Python permite aplicar decoradores de manera más elegante:

@debug_decorator
def sumar(*nums):
    resultado = 0
    for num in nums:
        resultado += num
    return resultado

sumar(1, 2) # 3
# => Args: (1, 2) {}
# => Resultado: 3

@debug_decorator reemplaza la función original por la versión decorada.

Podemos encadenar decoradores para agregar múltiples funcionalidades:

@debug_decorator
@time_decorator
def sumar(*nums):
    resultado = 0
    for num in nums:
        resultado += num
    return resultado

En este caso, la función sumar es primero transformada por time_decorator y luego por debug_decorator. Es decir, cuando se llama a sumar, primero se ejecuta debug_decorator y luego time_decorator

Decoradores con parámetros

¿Qué pasa si queremos modificar el comportamiento del decorador según una configuración? Podemos hacer un decorador con parámetros:

def decorador_con_params(param1, param2):
    def decorador_real(func):
        def wrapper(*args, **kwargs):
            print(f"Parámetros del decorador: {param1}, {param2}")
            resultado = func(*args, **kwargs)
            return resultado
        return wrapper
    return decorador_real

Aplicamos el decorador con valores personalizados:

@decorador_con_params("Info", 10)
def funcion_prueba():
    print("Función ejecutada")

funcion_prueba()
# => Parámetros del decorador: Info, 10
# => Función ejecutada

@decorador_con_params("Info", 10) personaliza el decorador.

Decorador que filtra datos

Creamos un decorador que filtra números antes de sumarlos:

def filtrar_por(filtro):
    def decorador(func):
        def wrapper(*args):
            args = filtro(args)
            print('Argumentos filtrados:', args)
            return func(*args)
        return wrapper
    return decorador

Definimos una función que filtra los números impares:

def impares(numeros):
    return [num for num in numeros if num % 2 == 1]

@filtrar_por(impares)
def sumar(*nums):
    return sum(nums)

sumar(3, 4, 5, 6) # 8
# => Argumentos filtrados: [3, 5]

Solo se suman los números impares.

Podemos hacer lo mismo con un filtro de límite:

def menor_que(maximo):
    def filtro(numeros):
        return [num for num in numeros if num < maximo]
    return filtro

@filtrar_por(menor_que(5))
def sumar(*nums):
    return sum(nums)

sumar(3, 4, 5, 6) # 7
# => Argumentos filtrados: [3, 4]

Solo suma los números menores a 5.

Resumen

  • Los decoradores permiten extender funciones sin modificar su código.
  • Son ampliamente usados en Python para:
    • Registro de logs (@logging)
    • Medición de tiempo (@timeit)
    • Autenticación en APIs (@auth_required)
    • Caché de resultados (@lru_cache)

Son una herramienta poderosa, pero deben usarse con cuidado para no afectar el rendimiento ni la claridad del código.

Para acceder completo a curso necesitas un plan básico

El plan básico te dará acceso completo a todos los cursos, ejercicios y lecciones de Códica, proyectos y acceso de por vida a la teoría de las lecciones completadas. La suscripción se puede cancelar en cualquier momento.

Obtener acceso
130
cursos
1000
ejercicios
2000+
horas de teoría
3200
test

Obtén acceso

Cursos de programación para principiantes y desarrolladores experimentados. Comienza tu aprendizaje de forma gratuita

  • 130 cursos, 2000+ horas de teoría
  • 1000 ejercicios prácticos en el navegador
  • 360 000 estudiantes
Al enviar el formulario, aceptas el «Política de privacidad» y los términos de la «Oferta», y también aceptas los «Términos y condiciones de uso»

Nuestros graduados trabajan en empresas como:

Bookmate
Health Samurai
Dualboot
ABBYY