Decorators Avançados e Parametrizados em Python: Padrões Profissionais
1. Revisão Rápida: Decorators Básicos
Um decorator básico é uma função que recebe outra função como argumento e retorna uma nova função:
def decorator_simples(func):
def wrapper(*args, **kwargs):
print("Antes da execução")
resultado = func(*args, **kwargs)
print("Depois da execução")
return resultado
return wrapper
@decorator_simples
def saudacao(nome):
print(f"Olá, {nome}!")
saudacao("Ana")
Saída:
Antes da execução
Olá, Ana!
Depois da execução
O decorator intercepta a chamada à função e adiciona lógica antes e depois da execução original.
2. Decorators Avançados
Decorators avançados geralmente envolvem:
Uso de
*args
e**kwargs
para funções genéricas.Encadeamento de múltiplos decorators.
Preservação da metadata da função com
functools.wraps
.Aplicação em métodos de classe e estáticos.
2.1 Preservando Metadata com functools.wraps
from functools import wraps
def log(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Chamando {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log
def soma(a, b):
"""Soma dois números."""
return a + b
print(soma.__name__) # soma
print(soma.__doc__) # Soma dois números.
Sem
@wraps
, a função decorada perde seu nome original e docstring, o que prejudica documentação e introspecção.
2.2 Encadeamento de Decorators
É possível aplicar vários decorators a uma função:
def dobro(func):
@wraps(func)
def wrapper(*args, **kwargs):
return 2 * func(*args, **kwargs)
return wrapper
@log
@dobro
def numero():
return 10
print(numero())
Saída:
Chamando numero
20
A ordem de aplicação importa: o decorator mais próximo da função é aplicado primeiro.
3. Decorators Parametrizados
Um decorator parametrizado é um decorator que aceita argumentos, permitindo customizar seu comportamento.
3.1 Exemplo Básico
from functools import wraps
def repetir(vezes):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
resultado = None
for _ in range(vezes):
resultado = func(*args, **kwargs)
return resultado
return wrapper
return decorator
@repetir(3)
def dizer_ola():
print("Olá!")
dizer_ola()
Saída:
Olá!
Olá!
Olá!
O decorator recebe o parâmetro
vezes
e cria um decorator interno que aplica a lógica.
3.2 Uso Profissional: Controle de Acesso
Decorators parametrizados são muito úteis em autenticação, autorização e logs customizados.
def permissao(roles_permitidos):
def decorator(func):
@wraps(func)
def wrapper(user, *args, **kwargs):
if user['role'] not in roles_permitidos:
raise PermissionError("Acesso negado!")
return func(user, *args, **kwargs)
return wrapper
return decorator
@permissao(['admin', 'moderador'])
def deletar_post(user, post_id):
print(f"Post {post_id} deletado pelo usuário {user['name']}")
usuario = {'name': 'Ana', 'role': 'admin'}
deletar_post(usuario, 42)
Permite controlar dinamicamente o acesso a funções sem poluir o código principal.
4. Decorators para Classes
Além de funções, decorators podem ser aplicados diretamente em classes:
def registrar_classe(cls):
print(f"Registrando classe {cls.__name__}")
return cls
@registrar_classe
class Produto:
pass
Útil para frameworks, plugins e automação de registro de classes.
5. Decorators Avançados com Padrões Profissionais
5.1 Memoization (Cache)
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(35)) # Calcula de forma eficiente
Evita recalcular resultados de funções puras, aumentando performance.
5.2 Logging e Auditoria
def auditar(acao):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Ação: {acao}, função: {func.__name__}, args: {args}, kwargs: {kwargs}")
return func(*args, **kwargs)
return wrapper
return decorator
@auditar("Atualizar estoque")
def atualizar_estoque(produto, quantidade):
print(f"{quantidade} unidades de {produto} atualizadas")
atualizar_estoque("Notebook", 5)
Decora funções com informações contextualizadas, útil para logs corporativos.
6. Boas Práticas
Use
functools.wraps
sempre para preservar metadata.Evite lógica pesada no decorator — delegue ao código principal ou helper functions.
Prefira decorators parametrizados para aumentar flexibilidade.
Combine com classes, mixins e metaclasses para sistemas avançados.
Documente bem — decorators podem confundir se aplicados em cascata.
Teste decoradores isoladamente — erros podem ser difíceis de rastrear.
7. Conclusão
Decorators avançados e parametrizados transformam funções simples em ferramentas poderosas, aplicáveis a logging, validação, caching, autorização e muito mais.
O uso de encadeamento de decorators,
functools.wraps
e parametrização é fundamental para padrões profissionais de Python.Combinando decorators com POO avançada, mixins e metaclasses, você consegue criar frameworks e sistemas robustos e altamente reutilizáveis.
Comentários
Postar um comentário