A Magia do Cache em Python: Desvendando functools.cache e Seus Segredos
Introdução
Se você já escreveu uma função custosa como uma chamada de API, uma busca em banco de dados ou um cálculo matemático complexo, provavelmente desejou que os resultados fossem reaproveitados sem precisar repetir o esforço. Python resolve isso com elegância através do módulo functools, e entre seus recursos mais poderosos e pouco explorados estão os decoradores @cache, @lru_cache e @cached_property. Este artigo explora esses recursos com exemplos práticos e mostra como eles podem melhorar significativamente o desempenho e a clareza do seu código.
functools.cache
A partir do Python 3.9, o decorador @cache permite armazenar em memória os resultados de funções puras, ou seja, funções que sempre retornam o mesmo resultado para os mesmos argumentos e não têm efeitos colaterais. Isso evita cálculos repetidos e acelera drasticamente a execução em chamadas futuras.
Exemplo prático
Sem o uso de cache, essa função teria desempenho exponencial e se tornaria inutilizável para valores altos de n. Com cache, até chamadas como fibonacci(1000) tornam-se viáveis.
functools.lru_cache
Se sua função recebe muitos argumentos diferentes e você quer limitar a memória usada, o decorador @lru_cache permite definir um limite de armazenamento. A sigla LRU significa Least Recently Used, e isso significa que apenas os N resultados mais usados recentemente são mantidos em cache.
Exemplo prático
Na segunda chamada com a mesma consulta, o resultado vem direto da memória sem executar a lógica interna. Se necessário, é possível limpar o cache com get_data_from_db.cache_clear().
functools.cached_property
Esse decorador transforma um método de instância em uma propriedade que é calculada apenas uma vez e armazenada. É muito útil para atributos derivados de outros valores do objeto que não mudam com o tempo, como um preço final baseado em preço base e imposto.
Exemplo prático
A primeira chamada executa o cálculo. A segunda reaproveita o valor armazenado.
Considerações importantes
Esses decoradores devem ser usados com funções puras que não dependem de estados externos ou efeitos colaterais. Evite aplicá-los a funções que recebem argumentos mutáveis como listas ou dicionários. Para medir os ganhos reais de desempenho, você pode usar o módulo timeit. E o melhor de tudo é que essas otimizações são aplicadas com uma única linha de código, sem reescrever algoritmos inteiros.
Conclusão
Os decoradores @cache, @lru_cache e @cached_property representam uma forma elegante e eficiente de aplicar caching em Python. Apesar de serem recursos nativos da linguagem, muitos desenvolvedores ainda não exploram todo o seu potencial. Compreendê-los e aplicá-los corretamente pode eliminar gargalos de performance, reduzir o consumo de recursos e tornar o código mais limpo e previsível.