Decorators em Python

0 – Python
8 – Orientada a Aspectos (AOP)
8.1 – Decorators para logging, cache, autenticação
8.2 – Monkey patching
8.3 – Descriptors (__get__, __set__)
LEGENDA
Nivel_1
Nivel_2
Nivel_3

Decorators são funções que modificam o comportamento de outras funções. Eles representam um recurso elegante da linguagem Python. Com um decorator, você adiciona funcionalidades sem alterar o código original. Isso promove o princípio DRY (Don’t Repeat Yourself). Além disso, eles resolvem problemas comuns de logging, cache e autenticação. Cada decorator atende uma necessidade específica de forma limpa. Por essa razão, eles se tornaram ferramentas indispensáveis. Assim, qualquer desenvolvedor Python deveria dominá-los.

Decorator para logging: rastreando execuções

O logging registra quando uma função é chamada e seus argumentos. Ele também captura o tempo de execução ou possíveis erros. Portanto, você obtém uma trilha útil para depuração em produção. Geralmente, aplicamos logging em funções críticas ou em APIs. Por exemplo, você pode logar todas as requisições a um banco. O decorator elimina a repetição manual de prints. Consequentemente, a manutenção do código fica muito mais simples. Além disso, você pode ativar ou desativar logs globalmente.

Uma fórmula mental para logging é:

\(\text{Log}(f) = \text{registro}(\text{entrada}) \rightarrow f \rightarrow \text{registro}(\text{saída})\)
Esse padrão anota algo antes e depois da função. Assim, você cria uma trilha completa de execução. Evite logar dados sensíveis como senhas ou tokens. Use níveis diferentes (INFO, DEBUG, ERROR) para organizar. Dessa maneira, o log fica útil sem poluir a saída.

Decorator para cache: acelerando repetições

O cache armazena resultados de funções com os mesmos argumentos. Quando a mesma chamada ocorre novamente, retornamos o valor imediato. Isso poupa tempo computacional em cálculos pesados. Operações de rede ou consultas lentas se beneficiam enormemente. Por outro lado, evite cache em funções que alteram estado externo. Um exemplo clássico é o cálculo recursivo de Fibonacci. Sem cache, sua complexidade se torna exponencial. Com cache, a complexidade cai para linear. Portanto, o cache é uma otimização poderosa.

A lógica do cache pode ser expressa assim:

\(\text{Cache}(f)(x) = \begin{cases} f(x) & \text{se } x \notin \text{memo} \\ \text{memo}[x] & \text{caso contrário} \end{cases}\)
Python já oferece functools.lru_cache para essa tarefa. Use cache quando sua função for pura e repetitiva. Primeiro, identifique gargalos de desempenho no seu sistema. Depois, adicione o decorator de cache nessas funções. Assim, você ganha velocidade sem alterar a lógica original.

Decorator para autenticação: protegendo acesso

A autenticação verifica se o usuário possui permissão antes da execução. Esse decorator aparece frequentemente em frameworks web como Flask. Ele pode checar um token, uma sessão ativa ou um papel. Se a verificação falhar, o decorator lança uma exceção. Dessa forma, o sistema impede ações não autorizadas. A lógica de segurança fica centralizada em um único local. Além disso, você nunca deve confiar apenas no front-end. A validação no back-end continua sendo obrigatória. Portanto, decorators de autenticação são indispensáveis.

Por exemplo, rotas administrativas ou exclusão de dados exigem papel admin. A função original roda exclusivamente para usuários autorizados. Caso contrário, o decorator retorna uma mensagem de erro. Esse padrão é amplamente adotado em sistemas reais. Sua clareza facilita auditorias de segurança. Ademais, você pode compor múltiplos decorators de autenticação. Isso permite criar hierarquias de permissões sofisticadas. Primeiro, defina os papéis disponíveis no sistema.

Código completo dos três decorators em python

Abaixo, apresentamos um exemplo funcional com logging, cache e autenticação. Cada decorator aparece separadamente para facilitar o entendimento. Observe como aplicamos eles com o símbolo @. A ordem dos decorators influencia o comportamento final. Primeiro, avalie qual camada deve executar primeiro. Geralmente, autenticação vem antes de logging. Cache geralmente fica na camada mais interna. Teste cada combinação para evitar surpresas indesejadas.

Neste código, o logging mostra cada chamada e seu respectivo tempo. O cache evita recálculos desnecessários da sequência de Fibonacci. A autenticação impede ações de usuários não autorizados. Primeiro, observe que as funções originais permanecem simples. Elas focam exclusivamente em sua tarefa principal. As preocupações transversais ficaram isoladas nos decorators. Essa abordagem segue as boas práticas da comunidade Python. Além disso, decorators empilhados executam de baixo para cima. Portanto, preste atenção na ordem ao combiná-los. Finalmente, teste sempre cada decorator individualmente. Isso garante que eles funcionem como você espera. Assim, você constrói sistemas mais robustos e organizados.

Deixe um comentário