1.Caching and lazy evaluation
@functools.lru_cache remembers a function's past results, so calling it again with the same arguments returns instantly. Lazy evaluation delays work until actually needed — sometimes it never is, avoiding it entirely.
Key features
- @lru_cache(maxsize=None) caches every distinct set of arguments a function was called with
- A cached function must be pure — caching one with side effects causes bugs
- lru_cache has real memory cost — every cached result stays until evicted or cleared
- A generator expression computes items on demand — a list comprehension computes it all now
- Lazy evaluation avoids unnecessary work; caching avoids repeated work — different savings
lru_cache — the interface worth knowing
- fib_cached(28)
- leads to n already in cache?
- n already in cache?
- leads to return cached result (yes)
- leads to compute fib(n-1) + fib(n-2) (no)
- return cached result — instant — 0.000175s total
- compute fib(n-1) + fib(n-2) — once per distinct n only
- leads to store in cache, return
- store in cache, return
Command
from functools import lru_cache
@lru_cache(maxsize=None)
def expensive_computation(x):
...@lru_cache remembers past results for pure functions but never detects staleness; lazy evaluation avoids unneeded work.