{}const=>[]async()letfn</>var
DesarrolloPython

Decoradores en Python: ampliamos la funcionalidad sin cambiar el código

Aprende a usar decoradores en Python para ampliar la funcionalidad de forma elegante. Analizamos ejemplos prácticos: registro, almacenamiento en caché, medición del tiempo de ejecución y verificación de derechos de acceso. Explicaciones claras con ejemplos de código para desarrolladores principiantes y experimentados.

К

Kodik

Autor

5 min de lectura

Imagina que estás desarrollando una aplicación web y necesitas registrar cada llamada a la API, verificar los derechos de acceso de los usuarios y medir el tiempo de ejecución de las funciones. Por supuesto, puedes copiar el mismo código en cada función, pero hay una forma más elegante: los decoradores. Esta es una de las herramientas más potentes de Python, que permite modificar el comportamiento de las funciones sin cambiar su código fuente.

¿Qué son los decoradores?

Un decorador es una función que toma otra función como argumento y devuelve una nueva función con funcionalidad extendida. ¿Suena complicado? En realidad, todo es más fácil de lo que parece.

def my_decorator(func):
    def wrapper():
        print("Something happens before the function is called")
        func()
        print("Something happens after calling the function")
    return wrapper

@my_decorator
def say_hello():
    print("Hi!")

say_hello()

Resultado de la ejecución:

Что-то происходит до вызова функции
Привет!
Что-то происходит после вызова функции

El símbolo @ es un azúcar sintáctico de Python. La entrada @my_decorator antes de la función es equivalente a say_hello = my_decorator(say_hello).

🔥 100.000+ estudiantes ya están con nosotros

¿Cansado de leer teoría?
¡Hora de programar!

Kodik — una app donde aprendes a programar con práctica. Mentor IA, lecciones interactivas, proyectos reales.

🤖 IA 24/7
🎓 Certificados
💰 Gratis
🚀 Empezar
Se unieron hoy

Decoradores con argumentos

Pero, ¿qué pasa si nuestra función toma parámetros? Para ello, utilizamos *args y **kwargs:

def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(times=3)
def greet(name):
    print(f"Hi, {name}!")

greet("Alexey")

Conclusión:

Привет, Алексей!
Привет, Алексей!
Привет, Алексей!

Aquí hemos creado un decorador con un parámetro que repite la llamada a la función un número determinado de veces.

Ejemplos prácticos de decoradores

Medición del tiempo de ejecución

import time
from functools import wraps

def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"The {func.__name__} function was executed in {end - start:.4f} seconds")
        return result
    return wrapper

@timer
def heavy_computation():
    time.sleep(2)
    return "Done"

heavy_computation()

Presta atención a @wraps(func): es un decorador integrado del módulo functools que almacena los metadatos de la función original (nombre, documentación, etc.).

Almacenamiento en caché de resultados

def memoize(func):
    cache = {}
    @wraps(func)
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrapper

@memoize
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(100))  # Se ejecutará instantáneamente gracias al almacenamiento en caché

Verificación de permisos

def require_auth(func):
    @wraps(func)
    def wrapper(user, *args, **kwargs):
        if not user.get('is_authenticated'):
            raise PermissionError("Authorization required")
        return func(user, *args, **kwargs)
    return wrapper

@require_auth
def delete_account(user, account_id):
    print(f"Account {account_id} has been deleted")

user = {'is_authenticated': True, 'username': 'admin'}
delete_account(user, 123)

Cadenas de decoradores

Los decoradores se pueden combinar aplicando varias funciones a una:

@timer
@memoize
def complex_calculation(x, y):
    time.sleep(1)
    return x ** y

# La primera llamada tardará ~1 segundo
complex_calculation(2, 10)

# La segunda llamada será instantánea (el resultado se almacena en caché)
complex_calculation(2, 10)

Los decoradores se aplican de abajo hacia arriba, es decir, primero memoize, luego timer.

Las clases como decoradores

Los decoradores no tienen que ser funciones. Se pueden utilizar clases:

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.count = 0
    
    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"Call #{self.count} of the {self.func.__name__} function"_}")
        return self.func(*args, **kwargs)

@CountCalls
def process_data():
    print("Processing data...")

process_data()
process_data()
process_data()

Decoradores integrados de Python

Python proporciona varios decoradores integrados útiles:

  • @property — convierte el método en un atributo de clase

  • @staticmethod — crea un método estático

  • @classmethod — crea un método de clase

  • @functools.lru_cache — almacenamiento en caché con restricción de tamaño

  • @dataclass - creación automática de métodos de clase

from functools import lru_cache

@lru_cache(maxsize=128)
def expensive_function(param):
    # Cálculos complejos
    return param * 2

Cuándo usar decoradores

Los decoradores son ideales para tareas que deben aplicarse a muchas funciones: registro, validación de datos de entrada, manejo de excepciones, control de acceso, almacenamiento en caché, medición de rendimiento, lógica de reintento para errores de red. Ayudan a cumplir con el principio DRY (Don't Repeat Yourself) y hacen que el código sea más limpio y claro.

Problemas potenciales

A pesar de todo el poder de los decoradores, hay que recordar algunos puntos. El uso excesivo de decoradores puede dificultar la depuración del código. Los decoradores añaden pequeños gastos generales al rendimiento. Es importante usar siempre @wraps para guardar los metadatos de la función. Las cadenas de muchos decoradores pueden reducir la legibilidad del código.

Currículum

Los decoradores son una forma elegante de modificar y ampliar la funcionalidad del código sin cambiarlo. Son ampliamente utilizados en marcos populares como Flask y Django, y comprender cómo funcionan hará tu vida como desarrollador mucho más fácil. Empieza con decoradores simples para registrar o medir el tiempo, y gradualmente encontrarás más y más situaciones en las que serán útiles.

¿Quieres dominar los decoradores y otras características avanzadas de Python en la práctica?

Anexo Kodik creado específicamente para que puedas aprender a programar a un ritmo cómodo, con explicaciones claras en ruso y ejemplos reales de la práctica. Analizamos temas complejos en un lenguaje sencillo, desde los conceptos básicos hasta las técnicas profesionales. Cada lección está estructurada de tal manera que no solo memorices la sintaxis, sino que entiendas cómo aplicar los conocimientos en proyectos reales.

Y si tienes alguna pregunta durante el proceso de aprendizaje, te damos la bienvenida a nuestro Canal de Telegram! Es una comunidad viva de desarrolladores donde puedes hacer cualquier pregunta y obtener una respuesta detallada. Nuestro ambiente es amigable e informativo: todos los días analizamos los principales temas en desarrollo, compartimos experiencias y nos ayudamos mutuamente a crecer. ¡Únete a Kodik y comienza tu viaje en la programación con aquellos que realmente entienden cómo hacer que el aprendizaje sea efectivo e interesante!

🎯Deja de postergar

¿Te gustó el artículo?
¡Hora de practicar!

En Kodik no solo lees — escribes código de inmediato. Teoría + práctica = habilidades reales.

Práctica instantánea
🧠IA explica código
🏆Certificado

Sin registro • Sin tarjeta