Caching and lazy evaluation
coreintermediate@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.
Think of it as
Caching is writing an answer on a sticky note the first time you work it out, so next time you just read the note. Lazy evaluation is not doing the work at all until someone actually asks for the answer — sometimes nobody ever does, and the work is avoided completely, not just sped up.
What we're doing: Measure a real speedup from lru_cache on recursive Fibonacci, where naive recursion recomputes the same values exponentially many times.
- 1
- The uncached version recomputes fib(n-2) millions of times across the recursive call tree — genuinely exponential work.
- 3
- @lru_cache means every distinct n is computed exactly once — the second call with the same n returns instantly from the cache.
uncached: 0.0648s
cached: 0.000175s
speedup: 370xWhy this works: Naive recursive Fibonacci recomputes the same sub-values an exponential number of times — fib(28) alone makes over a million redundant calls. Caching turns it into linear work: each distinct n computed exactly once, which is the direct, measured source of the 370x speedup.
Caching a function with mutable arguments or side effects
Wrong
Better
What you see: A cached function keeps returning the same result forever, even after the underlying data (a database row, a file) has actually changed.
Why: lru_cache has no concept of "this might be stale" — it caches forever (or until eviction) based purely on the arguments. It is only safe for genuinely pure, unchanging computations, not for anything backed by data that can change after the first call.
- 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
lru_cache — the interface worth knowing
Together
Remember: @lru_cache remembers past results for pure functions but never detects staleness; lazy evaluation avoids unneeded work.
See also: batching and connection pooling · functools module · lazy evaluation

