functools
functools fornece funções de ordem superior para cache, aplicação parcial, redução e genéricos de despacho único - blocos de construção comuns em decoradores e APIs.
Receita
from functools import lru_cache, partial
@lru_cache(maxsize=128)
def fib(n: int) -> int:
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
double = partial(pow, 2)Quando usar isso:
- Memoizar funções puras dispendiosas
- Currying de configuração em callbacks
- Escrever decoradores que preservam
__name__ - Comportamento de função específico do tipo sem cadeias
if isinstance
Exemplo de Trabalho
from functools import lru_cache, partial, reduce, singledispatch, wraps
def logger(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
print(f"chamada {fn.__name__}")
return fn(*args, **kwargs)
return wrapper
@logger
@lru_cache(maxsize=32)
def tokenize(text: str) -> tuple[str, ...]:
return tuple(text.lower().split())
@singledispatch
def serialize(value) -> str:
return str(value)
@serialize.register(int)
def _(value: int) -> str:
return f"i:{value}"
def product(nums: list[int]) -> int:
return reduce(lambda a, b: a * b, nums, 1)
if __name__ == "__main__":
print(tokenize("Hello World"))
print(serialize(42))
print(product([2, 3, 4]))
add5 = partial(lambda a, b: a + b, 5)
print(add5(10))O que isso demonstra:
@wrapscopia metadados para o wrapper para introspecção/depuraçãolru_cacherequer argumentos hashablesingledispatchregistra manipuladores por tiporeducecombina um iterável com uma função binária
Mergulho Profundo
Como Funciona
- lru_cache - Dicionário indexado por argumentos; descarta o menos recentemente usado em
maxsize. - cache_clear - Invalida resultados memorizados quando as entradas mudam externamente.
- partial -
partial(func, *args, **kwargs)fixa os argumentos iniciais. - singledispatch - Despacha com base no tipo do primeiro argumento; registra com decorador.
- total_ordering - Gera métodos de comparação a partir de
__eq__e um de ordenação.
Ordem da Pilha de Decoradores
@outer
@inner
def f(): ...
# é igual a f = outer(inner(f)) - inner aplicado primeiroNotas Python
from functools import cached_property # 3.8+
class Config:
@cached_property
def heavy(self) -> dict:
return load()Armadilhas
- lru_cache com argumentos mutáveis - Listas não são hashable. Correção: Argumentos tupla ou desativar cache.
- Cache de funções impuras - Leituras obsoletas quando o estado oculto muda. Correção:
cache_clearou sem cache. - Cache ilimitado
maxsize=None- Crescimento de memória em espaço de chave infinito. Correção: Definirmaxsize. partialobscurece a assinatura -inspectmenos claro. Correção: Wrapper com parâmetros explícitos para APIs públicas.singledispatchnão para múltiplos argumentos - Apenas o tipo do primeiro argumento. Correção: Bibliotecas multimétodo ou correspondência manual.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| cache de dicionário manual | Evicção customizada | lru_cache é suficiente |
@cache (3.9+) | Espaço de chave pequeno e ilimitado | Necessita de evicção LRU |
match/case dispatch | Poucos tipos inline | Extensão aberta entre módulos |
itertools.accumulate | Dobra em execução sem importação de reduce | Necessita apenas do valor final único |
FAQs
lru_cache vs cache?
functools.cache é um cache simples e ilimitado semelhante a LRU (3.9+). lru_cache controla o tamanho e as estatísticas.
lru_cache thread-safe?
CPython protege o dicionário de cache para operações únicas - ainda coordene se a função subjacente não for thread-safe.
quando usar partial?
Vincular callbacks de configuração - partial(send_email, smtp=cfg) em loops.
wraps é necessário?
Sim para decoradores públicos - preserva __name__, __doc__, anotações para ferramentas.
reduce ainda é pythonic?
Aceitável para dobras funcionais; muitas vezes mais claro total = 1; for x in nums: total *= x para iniciantes.
extensão singledispatch?
Registre em outros módulos com o mesmo nome de função importado - a ordem importa.
cached_property vs lru_cache?
cached_property armazena no instância uma vez; lru_cache nos argumentos da função globalmente.
ressalva total_ordering?
Deve definir __eq__ e uma comparação; outros são derivados - pode ser mais lento que o manual.
cache_info?
fib.cache_info() mostra acertos/erros, maxsize/currsize para ajuste.
functools em caminho crítico?
lru_cache ajuda chamadas puras dispendiosas; partial tem custo insignificante.
Relacionado
- Escrevendo Decoradores - padrão
wraps - Closures & Captura de Escopo - padrão de fábrica
- Sobrecargas & Tipos Chamáveis - sobrecargas de tipagem
- itertools -
accumulatevsreduce
Versões da Pilha: Esta página foi escrita para Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.