Saltar al contenido principal
Python intermedio2026-07-29 · 10 min de lectura

Explicación de los decoradores de Python: de @property a reintentar la lógica en 15 minutos (2026)

Los decoradores son la característica que separa "conoce Python" de "lee Python con fluidez". Parecen mágicos, pero son mecánicos: @decorator en una función es exactamente f = decorador(f). Eso es todo. Todo lo demás en este tutorial es esa línea aplicada en diferentes formas.

La teoría de una línea

Cuando escribes:

▶ PYTHONeditable · runs in your browser

Python lo transforma en:

▶ PYTHONeditable · runs in your browser

Esa es la mecánica completa. @decorator_name encima de def ejecuta def_name = decorator_name(def_name) después de la definición. Si interiorizas esto, los decoradores dejarán de ser misteriosos para siempre.

Escribiendo tu primer decorador (60 segundos)

Un decorador es cualquier elemento invocable que toma una función y devuelve una función. La forma típica:

▶ PYTHONeditable · runs in your browser

Los *args, **kwargs en el contenedor es un patrón defensivo: permite al decorador trabajar en cualquier función independientemente de la firma. Sáltelo y obtendrá "TypeError: wrapper() toma 0 argumentos posicionales pero se dieron 2" en el momento en que alguien decora una función con parámetros.

La solución @functools.wraps

Un error sutil: después de decorar, "add.__name__ es "envoltorio", no "add". Las cadenas de documentación y las sugerencias de tipo también desaparecen. La solución es una importación:

▶ PYTHONeditable · runs in your browser

Regla: cada decorador que escriba debe usar `@functools.wraps(fn)`. Cuesta una línea y evita toda una categoría de problemas de depuración (introspección, accesorios pytest, formateadores logging, pickle: todos se rompen silenciosamente sin él).

Los cuatro decoradores que verás en cada código base

1. @property — atributos calculados

▶ PYTHONeditable · runs in your browser

@property hace que un método sea invocable como si fuera un atributo. Perfecto para valores derivados de solo lectura. También existe @area.setter para la ruta de escritura, pero el 90% de los usos de @property son de solo lectura.

2. @staticmethod y @classmethod

▶ PYTHONeditable · runs in your browser

@classmethod obtiene cls (la clase misma) y se usa para constructores alternativos. @staticmethod no tiene nada de especial y es una función simple que se encuentra dentro del espacio de nombres de la clase.

3. @functools.cache — memorización

▶ PYTHONeditable · runs in your browser

Uno de los decoradores stdlib más poderosos. Memoriza automáticamente la función en función de sus argumentos. Requiere que todos los argumentos sean hash (sin listas/dictados como argumentos; use tuplas).

4. @dataclasses.dataclass — eliminación repetitiva

▶ PYTHONeditable · runs in your browser

@dataclass lee las anotaciones de tipo de nivel de clase y genera __init__, __repr__, __eq__ y (con frozen=True) __hash__ automáticamente. Es la mayor mejora en la calidad de vida en Python 3.7+.

Escribir un decorador @retry (ejemplo del mundo real)

Un decorador que reintenta una función en caso de falla con retroceso exponencial:

▶ PYTHONeditable · runs in your browser

Observe las tres funciones anidadas: retry acepta los argumentos de configuración y devuelve decorador; decorador acepta la función y devuelve wrapper; wrapper ejecuta el ciclo de reintento. Este patrón de tres capas es lo que parece cualquier decorador con argumentos: memoriza la forma, no el ejemplo específico.

Decoradores basados en clases (raros pero útiles)

Un decorador es cualquier invocable. Las clases con __call__ también funcionan:

▶ PYTHONeditable · runs in your browser

Úselo cuando el decorador necesite mantener un estado que sobreviva a una sola llamada (un contador, un caché, un depósito de límite de velocidad).

Errores comunes

1. Olvidar `@functools.wraps`: la introspección se interrumpe silenciosamente.

2. Argumentos predeterminados mutables en el propio decorador: aquí también aparece el clásico error def wrapper(x, cache=[]).

3. Decorar métodos sin aceptar `self` — recuerda que self es solo un argumento posicional; *args, **kwargs lo capta bien.

4. El orden es importante al apilar: @a\n@b\ndef f() es f = a(b(f)). Lea las pilas de abajo hacia arriba.

Practica

Escriba un decorador @timing que imprima cuánto tiempo tarda en ejecutarse la función envuelta, luego aplíquelo a una función que calcule sum(range(10_000_000)). El decorador completo tiene 8 líneas con functools.wraps + time.perf_counter.


Una vez que internalizas que @x es f = x(f), los decoradores se convierten en una de las características más productivas de Python. Están en todas partes en bases de código reales: rutas Flask/FastAPI (@app.route), dispositivos pytest (@pytest.fixture), vistas Django (@login_required), validadores Pydantic (@field_validator). Aprender a escribirlos usted mismo desbloquea la capacidad de leer cada uno de ellos.

Siguiente paso: 10 lecciones prácticas de decorador: cree @retry, @memoise, @rate_limit y @requires_auth desde cero con Python real ejecutándose en su navegador.

¿Listo para probarlo?

15 lecciones gratis después de un registro gratuito, sin tarjeta. Pruebe la plataforma y luego decida.

Empieza gratis →

Or unlock every lesson

Pro — $12/mo, unlimited AI, cancel any time. Refund within 14 days worldwide.

See Pro plans →

Get one Python lesson + one career idea every Friday

No spam, no "buy our course now". Three bullets, every Friday. Unsubscribe with one click.