Decoradores en Python: qué son, cómo funcionan y para qué sirven

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Qué son los decoradores en Python

Si llevas más de una semana programando en Python, seguro has visto el símbolo @ sobre una función. Eso es un decorador, una herramienta poderosa y elegante de programación.

Los decoradores en Python permiten "envolver" una función dentro de otra. Modifican o extienden el comportamiento de una función sin alterar su código original. Se usan en todas partes: Flask, Django, FastAPI, pytest, e incluso en la biblioteca estándar de Python.

Cómo funcionan los decoradores

Fundamentos de los decoradores

Un decorador es una función que recibe otra función y devuelve una nueva función o la original modificada.

def decorador(func):
    def wrapper():
        print("Antes de la llamada")
        func()
        print("Después de la llamada")
    return wrapper

@decorador
def saludar():
    print("¡Hola!")

saludar()

Resultado:

Antes de la llamada
¡Hola!
Después de la llamada

El símbolo @decorador es azúcar sintáctico para escribir:

saludar = decorador(saludar)

Estructura interna de los decoradores

Para entender los decoradores en Python, necesitas conocer estos conceptos clave:

  • En Python, las funciones son objetos de primera clase
  • Las funciones se pueden pasar como argumentos a otras funciones
  • Dentro de las funciones se pueden definir otras funciones
  • Existe el mecanismo de cierre (closure)

Plantilla universal de un decorador

La plantilla mínima de un decorador es la siguiente:

def decorador(func):
    def wrapper(*args, **kwargs):
        # Acciones antes de ejecutar la función
        resultado = func(*args, **kwargs)
        # Acciones después de ejecutar la función
        return resultado
    return wrapper

Ejemplos prácticos de decoradores

Decorador para medir tiempo de ejecución

import time

def temporizador(func):
    def wrapper(*args, **kwargs):
        inicio = time.time()
        resultado = func(*args, **kwargs)
        tiempo_ejecucion = time.time() - inicio
        print(f"{func.__name__} tardó {tiempo_ejecucion:.4f} seg")
        return resultado
    return wrapper

@temporizador
def funcion_lenta():
    time.sleep(1)
    return "Operación completada"

funcion_lenta()

Este decorador es útil para medir el rendimiento de funciones y optimizar código.

Decorador de verificación de autenticación

def requerir_admin(func):
    def wrapper(usuario, *args, **kwargs):
        if usuario != "admin":
            raise PermissionError("Acceso denegado")
        return func(usuario, *args, **kwargs)
    return wrapper

@requerir_admin
def eliminar_base_datos(usuario):
    print("¡Base de datos eliminada!")
    return True

eliminar_base_datos("admin")  # Ejecución exitosa

Este decorador mejora la seguridad de la aplicación al controlar el acceso a funciones críticas.

Decorador de registro (logging)

import logging
from functools import wraps

def registrar_llamadas(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        logging.info(f"Llamada a función {func.__name__} con argumentos {args}, {kwargs}")
        try:
            resultado = func(*args, **kwargs)
            logging.info(f"Función {func.__name__} ejecutada correctamente")
            return resultado
        except Exception as e:
            logging.error(f"Error en función {func.__name__}: {e}")
            raise
    return wrapper

Decoradores con argumentos

Creación de una fábrica de decoradores

Cuando un decorador necesita recibir parámetros, se crea una fábrica de decoradores:

def repetir(n):
    def decorador(func):
        def wrapper(*args, **kwargs):
            resultados = []                

Blogs

Book Recommendations