Saltar para o conteúdo principal
Python intermediário2026-07-29 · 10 min de leitura

Explicação dos decoradores Python: de @property para tentar novamente a lógica em 15 minutos (2026)

Decoradores são o recurso que separa "conhece Python" de "lê Python fluentemente". Eles parecem mágicos, mas são mecânicos: @decorator em uma função é exatamente f = decorator(f). É isso. Todo o resto neste tutorial é aquela linha aplicada em diferentes formas.

A teoria de uma linha

Quando você escreve:

▶ PYTHONeditable · runs in your browser

Python o transforma em:

▶ PYTHONeditable · runs in your browser

Essa é a mecânica inteira. @decorator_name acima de def executa def_name = decorator_name(def_name) após a definição. Se você internalizar isso, os decoradores deixam de ser misteriosos para sempre.

Escrevendo seu primeiro decorador (60 segundos)

Um decorador é qualquer callable que recebe uma função e retorna uma função. A forma típica:

▶ PYTHONeditable · runs in your browser

O *args, **kwargs no wrapper é um padrão defensivo - permite que o decorador trabalhe em qualquer função, independentemente da assinatura. Ignore-o e você obterá TypeError: wrapper() takes 0 positional arguments but 2 were given no momento em que alguém decora uma função com parâmetros.

A correção @functools.wraps

Um bug sutil: depois de decorar, add.__name__ é "wrapper", não "add". Documentos e dicas de tipo também desaparecem. A correção é uma importação:

▶ PYTHONeditable · runs in your browser

Regra: todo decorador que você escreve deve usar `@functools.wraps(fn)`. Custa uma linha e evita uma categoria inteira de problemas de depuração (introspecção, fixtures pytest, formatadores logging, pickle - todos quebram silenciosamente sem ele).

Os quatro decoradores que você verá em cada base de código

1. @property — atributos computados

▶ PYTHONeditable · runs in your browser

@property torna um método chamável como se fosse um atributo. Perfeito para valores derivados somente leitura. Há também @area.setter para o caminho de gravação, mas 90% dos usos de @property são somente leitura.

2. @staticmethod e @classmethod

▶ PYTHONeditable · runs in your browser

@classmethod obtém cls (a própria classe) e é usado para construtores alternativos. @staticmethod não tem nada de especial e é uma função simples que reside dentro do namespace da classe.

3. @functools.cache — memorização

▶ PYTHONeditable · runs in your browser

Um dos decoradores stdlib mais poderosos. Memoriza automaticamente a função com base em seus argumentos. Requer que todos os argumentos sejam hasháveis ​​(sem listas/dictos como argumentos - use tuplas).

4. @dataclasses.dataclass — eliminação padrão

▶ PYTHONeditable · runs in your browser

@dataclass lê as anotações de tipo em nível de classe e gera __init__, __repr__, __eq__ e (com frozen=True) __hash__ automaticamente. É a maior melhoria de qualidade de vida no Python 3.7+.

Escrevendo um decorador @retry (exemplo do mundo real)

Um decorador que tenta novamente uma função em caso de falha com espera exponencial:

▶ PYTHONeditable · runs in your browser

Observe as três funções aninhadas: retry aceita os argumentos de configuração e retorna decorator; decorator aceita a função e retorna wrapper; wrapper executa o loop de nova tentativa. Este padrão de três camadas é a aparência de qualquer decorador com argumentos - memorize a forma, não o exemplo específico.

Decoradores baseados em classes (raros, mas úteis)

Um decorador pode ser chamado por qualquer pessoa. Aulas com __call__ também funcionam:

▶ PYTHONeditable · runs in your browser

Use quando o decorador precisar manter um estado que sobreviva a uma única chamada (um contador, um cache, um intervalo de limite de taxa).

Armadilhas comuns

1. Esquecendo `@functools.wraps` — a introspecção é interrompida silenciosamente.

2. Argumentos padrão mutáveis ​​no próprio decorador — o bug clássico def wrapper(x, cache=[]) aparece aqui também.

3. Decorar métodos sem aceitar `self` — lembre-se que self é apenas um argumento posicional; *args, **kwargs pega bem.

4. A ordem é importante ao empilhar: @a\n@b\ndef f() é f = a(b(f)). Leia as pilhas de baixo para cima.

Prática

Escreva um decorador @timing que imprima quanto tempo a função encapsulada leva para ser executada e, em seguida, aplique-o a uma função que calcula sum(range(10_000_000)). Todo o decorador tem 8 linhas com functools.wraps + time.perf_counter.


Depois de internalizar que @x é f = x(f), os decoradores se tornam um dos recursos mais produtivos do Python. Eles estão por toda parte em bases de código reais: rotas Flask/FastAPI (@app.route), fixtures pytest (@pytest.fixture), visualizações Django (@login_required), validadores Pydantic (@field_validator). Aprender a escrevê-los sozinho desbloqueia a capacidade de ler cada um deles.

Próxima etapa: 10 aulas práticas de decorador — crie @retry, @memoise, @rate_limit e @requires_auth do zero com Python real rodando em seu navegador.

Pronto para experimentar?

15 aulas gratuitas após uma inscrição gratuita - sem cartão. Experimente a plataforma e depois decida.

Comece gratuitamente →

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.