Decoradores em Python – O que são e como usar
Neste artigo, vamos explorar em detalhes:
O que são decoradores.
Como funcionam funções como objetos de primeira classe.
Criando decoradores simples e avançados.
Decoradores com argumentos.
Aplicações práticas em projetos reais.
Decoradores prontos da biblioteca padrão.
Boas práticas e armadilhas comuns.
1) Funções como objetos de primeira classe
Em Python, funções são objetos. Isso significa que podemos:
Atribuir funções a variáveis.
Passar funções como argumento para outras funções.
Retornar funções de dentro de funções.
Exemplo básico:
def saudacao():
return "Olá!"
f = saudacao # atribuímos a função a uma variável
print(f()) # chama a função normalmente → "Olá!"
Isso é essencial para entender decoradores, já que eles usam exatamente esse recurso.
2) Funções internas (closures)
Podemos definir funções dentro de funções:
def externa():
def interna():
print("Função interna chamada!")
interna()
externa()
Funções internas podem capturar variáveis da função externa (closure):
def multiplicador(fator):
def interno(valor):
return valor * fator
return interno
dobro = multiplicador(2)
print(dobro(10)) # 20
Esse conceito é a base dos decoradores.
3) O que é um decorador?
Um decorador é, essencialmente, uma função que recebe outra função como parâmetro e retorna uma nova função (modificada ou expandida).
Exemplo simples:
def meu_decorador(func):
def wrapper():
print("Antes da função")
func()
print("Depois da função")
return wrapper
@meu_decorador
def diz_oi():
print("Oi!")
diz_oi()
Saída:
Antes da função
Oi!
Depois da função
Note o uso do @meu_decorador — essa é apenas açúcar sintático para:
diz_oi = meu_decorador(diz_oi)
4) Decoradores com argumentos da função original
O wrapper precisa receber *args e **kwargs para suportar funções com parâmetros:
def log_calls(func):
def wrapper(*args, **kwargs):
print(f"Chamando {func.__name__} com args={args}, kwargs={kwargs}")
resultado = func(*args, **kwargs)
print(f"{func.__name__} retornou {resultado}")
return resultado
return wrapper
@log_calls
def soma(a, b):
return a + b
soma(3, 5)
5) Decoradores com argumentos próprios
Às vezes queremos que o decorador receba parâmetros. Para isso, criamos uma função que retorna o decorador:
def repetir(n):
def decorador(func):
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorador
@repetir(3)
def oi():
print("Oi!")
oi()
Saída:
Oi!
Oi!
Oi!
6) Mantendo metadados da função original
Um problema: ao decorar funções, o wrapper substitui metadados como __name__ e __doc__.
Solução: usar functools.wraps.
from functools import wraps
def meu_decorador(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
Agora, help(func) e func.__name__ mostram os dados corretos.
7) Decoradores aplicados a métodos
Decoradores funcionam da mesma forma em métodos de classe:
def debug(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"[DEBUG] {func.__name__} chamado")
return func(*args, **kwargs)
return wrapper
class Calculadora:
@debug
def soma(self, a, b):
return a + b
c = Calculadora()
print(c.soma(2, 3))
8) Decoradores aplicados a classes
Um decorador também pode receber uma classe e retornar uma versão modificada dela:
def add_repr(cls):
def __repr__(self):
return f"{cls.__name__}({self.__dict__})"
cls.__repr__ = __repr__
return cls
@add_repr
class Pessoa:
def __init__(self, nome):
self.nome = nome
p = Pessoa("João")
print(p) # Pessoa({'nome': 'João'})
9) Aplicações práticas de decoradores
Logging e debug
Registra chamadas e retornos de funções.Autenticação/autorização
Em Flask/Django, verifica se o usuário está logado antes de acessar uma rota.Cache/memoization
Guarda resultados para não recalcular.Retry automático
Repete execução em caso de falha.Medição de tempo
Calcula quanto tempo uma função levou para rodar.
Exemplo de medição de tempo:
import time
def tempo_execucao(func):
@wraps(func)
def wrapper(*args, **kwargs):
inicio = time.time()
resultado = func(*args, **kwargs)
fim = time.time()
print(f"{func.__name__} executou em {fim - inicio:.4f}s")
return resultado
return wrapper
@tempo_execucao
def tarefa():
time.sleep(1)
tarefa()
10) Decoradores prontos no Python
Python já oferece decoradores úteis:
@staticmethod→ transforma método em estático.@classmethod→ método recebeclsem vez deself.@property→ cria propriedades (atributos calculados).functools.lru_cache→ cache automático de chamadas.
Exemplo lru_cache:
from functools import lru_cache
@lru_cache(maxsize=128)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
print(fib(35)) # executa rápido devido ao cache
11) Decoradores aninhados (stacking)
Você pode empilhar decoradores:
@tempo_execucao
@log_calls
def processar():
return sum(i*i for i in range(10**5))
A ordem importa: o decorador mais próximo da função é aplicado primeiro.
12) Decoradores avançados: registrando plugins
Decoradores também são ótimos para registrar funções automaticamente:
plugins = {}
def registrar(nome):
def decorador(func):
plugins[nome] = func
return func
return decorador
@registrar("soma")
def soma(a, b):
return a + b
@registrar("mult")
def mult(a, b):
return a * b
print(plugins["soma"](2, 3)) # 5
print(plugins["mult"](2, 3)) # 6
Isso é usado em sistemas de comandos, APIs de plugins, frameworks.
13) Boas práticas com decoradores
Sempre use
functools.wrapspara manter metadados.Mantenha decoradores pequenos e focados em uma responsabilidade.
Evite lógica complexa dentro de decoradores.
Use decoradores aninhados com cautela (pode dificultar debugging).
Documente bem decoradores que serão usados por outros desenvolvedores.
Conclusão
Decoradores em Python oferecem uma forma limpa e reutilizável de adicionar comportamentos às funções, métodos e classes. Do logging ao cache, da autorização ao plugin system, eles tornam seu código mais modular, expressivo e poderoso.
Se você ainda não usa decoradores nos seus projetos, experimente começar simples (um medidor de tempo, por exemplo) e vá evoluindo para usos mais avançados — você vai perceber como eles podem deixar seu código muito mais elegante.

Comentários
Postar um comentário