Decorators em Python

0 – Python
6 – Funcional
6.1 – Funcoes puras
6.2 – Imutabilidade (tuplas, frozenset, namedtuple)
6.3 – Funcoes de alta ordem (map, filter, reduce)
6.4 – Comprehensions (list, dict, set)
6.5 – Geradores (yield, generator expressions)
6.6 – Decorators (@)
6.7 – Closures
6.8 – Funcoes lambda
LEGENDA
Nivel_1
Nivel_2
Nivel_3

Decorators são funções que modificam o comportamento de outras funções. Eles usam o símbolo @ antes da definição da função. Primeiramente, decorators envolvem uma função para estendê-la. Por exemplo, @timer pode medir o tempo de execução. Além disso, decorators permitem reutilizar código de forma elegante. Assim, você evita repetir a mesma lógica em várias funções. Consequentemente, o código fica mais seco e manutenível. Quando utilizar decorators? Em logging, cache, autenticação e validação. Também para controle de acesso e medição de performance. Por outro lado, evite decorators para lógica muito específica. Python tem decorators nativos como @staticmethod e @property. Então, vamos explorar como criar e usar decorators personalizados. Três subtítulos guiarão você pelo mundo dos decorators. Portanto, ao final, você adicionará poderosas funcionalidades às suas funções.

Criando decorators básicos

Um decorator é uma função que recebe outra função como argumento. Ele retorna uma nova função que substitui a original. Quando usar decorators básicos? Para adicionar comportamento antes/depois. Por exemplo, logging, timing ou autenticação simples. Além disso, sempre preserve os metadados com @wraps. Exemplo de decorators básicos:

Decorators básicos são simples e extremamente úteis. Eles separam preocupações transversais do código principal. Portanto, use-os para funcionalidades repetitivas.

Decorators com argumentos e parâmetros

Decorators podem receber argumentos para serem configuráveis. A estrutura tem três níveis: decorator, wrapper interna e função. Quando usar decorators com argumentos? Em comportamentos parametrizáveis. Por exemplo, limites de tempo, contagem de tentativas ou níveis de log. Assim, você cria decorators reutilizáveis e flexíveis. Exemplo de decorators com argumentos:

Decorators com argumentos oferecem grande flexibilidade. Eles permitem configurar o comportamento dinamicamente. Portanto, use-os para criar ferramentas reutilizáveis.

Decorators práticos: autenticação e validação

Decorators são excelentes para validação e controle de acesso. Eles verificam pré-condições antes de executar a função. Quando usar esses decorators? Em APIs, rotas web e sistemas de permissão. Por exemplo, verificar se usuário está logado ou dados são válidos. Além disso, eles centralizam a lógica de segurança. Exemplo de decorators práticos:

Decorators são ferramentas essenciais no dia a dia do Python. A fórmula de um decorator pode ser expressa assim: \(D(f) = \text{wrapper} \quad \text{onde} \quad \text{wrapper} \approx \text{antes} + f + \text{depois}\) Use decorators para separar preocupações transversais. Seu código será mais limpo, modular e reutilizável. Portanto, comece com decorators simples e avance para os mais complexos. Finalmente, pratique criando seus próprios decorators.

Geradores em Python

python
0 – Python
6 – Funcional
6.1 – Funcoes puras
6.2 – Imutabilidade (tuplas, frozenset, namedtuple)
6.3 – Funcoes de alta ordem (map, filter, reduce)
6.4 – Comprehensions (list, dict, set)
6.5 – Geradores (yield, generator expressions)
6.6 – Decorators (@)
6.7 – Closures
6.8 – Funcoes lambda
LEGENDA
Nivel_1
Nivel_2
Nivel_3

Geradores são funções que produzem valores um de cada vez. Eles usam yield em vez de return para pausar a execução. Primeiramente, geradores economizam memória para grandes sequências. Por exemplo, range(1000000) é um gerador, não uma lista. Além disso, geradores podem produzir sequências infinitas. A voz passiva é usada aqui: “os valores são gerados sob demanda, não antecipadamente”. Quando utilizar geradores? Em processamento de grandes arquivos. Também em fluxos de dados infinitos e pipelines eficientes. Python oferece funções geradoras (yield) e expressões geradoras. Vamos explorar ambos os tipos com exemplos práticos. Três subtítulos guiarão você pelo universo dos geradores. Ao final, você economizará memória e processamento significativamente.

Funções geradoras com yield

Uma função geradora usa yield em vez de return. Ela retorna um objeto gerador, não uma lista completa. Cada yield pausa a função e guarda seu estado. Quando usar funções geradoras? Em sequências complexas. Por exemplo, Fibonacci, números primos ou leitura de arquivos grandes. A voz passiva é aplicada: “o estado da função é preservado entre chamadas”. Exemplo de funções geradoras:

Geradores com yield são poderosos e eficientes. Eles permitem pausar e retomar a execução livremente.

Expressões geradoras: generator expressions

Generator expressions são como list comprehensions, mas com parênteses. Elas produzem valores sob demanda, não uma lista inteira. A sintaxe é (expressão for item in iterável). Quando usar generator expressions? Em transformações de dados grandes. Também quando você só precisa iterar uma vez sobre os valores. A voz passiva é aplicada: “os elementos são produzidos um por um”. Exemplo de generator expressions:

Generator expressions economizam memória drasticamente. Elas são ideais para processamento de grandes volumes de dados.

Comparando geradores com listas e aplicações práticas

Geradores são melhores para grandes volumes de dados. Listas são melhores quando você precisa acessar múltiplas vezes. Quando usar cada um? Listas para dados pequenos e reuso. Geradores para streams grandes e iteração única. A voz passiva é aplicada: “os dados são processados em fluxo contínuo”. Exemplo prático e comparação detalhada:

Geradores são fundamentais para programação eficiente. A fórmula da economia de memória com geradores: \(M_{\text{gerador}} \approx O(1) \quad \text{vs} \quad M_{\text{lista}} \approx O(n)\) Use geradores para grandes volumes de dados. Use listas quando precisar de acesso aleatório múltiplo. Geradores com yield são ideais para sequências complexas. Generator expressions são perfeitas para transformações simples. Seu código será mais eficiente e escalável com geradores.