functools
functools supplies higher-order functions for caching, partial application, reduction, and single-dispatch generics - common building blocks in decorators and APIs.
Search across all documentation pages
functools supplies higher-order functions for caching, partial application, reduction, and single-dispatch generics - common building blocks in decorators and APIs.
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)When to reach for this:
__name__if isinstance chainsfrom functools import lru_cache, partial, reduce, singledispatch, wraps
def logger(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
print(f"call {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))What this demonstrates:
@wraps copies metadata to wrapper for introspection/debugginglru_cache requires hashable argumentssingledispatch registers per-type handlersreduce folds iterable with binary functionpartial(func, *args, **kwargs) fixes leading arguments.__eq__ and one ordering.@outer
@inner
def f(): ...
# equals f = outer(inner(f)) - inner applied firstfrom functools import cached_property # 3.8+
class Config:
@cached_property
def heavy(self) -> dict:
return load()
| Alternative | Use When | Don't Use When |
|---|---|---|
| manual dict cache | Custom eviction | lru_cache suffices |
@cache (3.9+) | Unbounded small key space | Need LRU eviction |
| match/case dispatch | Few types inline | Open extension across modules |
itertools.accumulate | Running fold without reduce import | Need final single value only |
functools.cache unbounded LRU-like simple cache (3.9+). lru_cache controls size and stats.
CPython protects cache dict for single operations - still coordinate if underlying function not thread-safe.
Bind config callbacks - partial(send_email, smtp=cfg) in loops.
Yes for public decorators - preserves __name__, __doc__, annotations for tooling.
Acceptable for functional folds; often clearer total = 1; for x in nums: total *= x for beginners.
Register in other modules with same function name imported - order matters.
cached_property stores on instance once; lru_cache on function arguments globally.
Must define __eq__ and one comparison; others derived - can be slower than manual.
fib.cache_info() hits/misses/maxsize/currsize for tuning.
lru_cache helps expensive pure calls; partial negligible cost.
Stack versions: This page was written for 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+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026