How to Memoize Pure Functions with functools.lru_cache in Python

Use functools.lru_cache to memoize a pure Fibonacci function and avoid recomputing repeated values.

Easy Python 3.9+ Aug 9, 2026 Concurrency & performance 15 views 0 copies

Python code

17 lines
Python 3.9+
from functools import lru_cache


@lru_cache(maxsize=128)
def fibonacci(n: int) -> int:
    """Return the nth Fibonacci number (0-indexed) using memoization."""
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)


if __name__ == "__main__":
    for i in range(10):
        print(f"fibonacci({i}) = {fibonacci(i)}")

    print(f"Cache info: {fibonacci.cache_info()}")
    print(f"Cache hit rate: {fibonacci.cache_info().hits / fibonacci.cache_info().currsize:.2f}")

Output

stdout
fibonacci(0) = 0
fibonacci(1) = 1
fibonacci(2) = 1
fibonacci(3) = 2
fibonacci(4) = 3
fibonacci(5) = 5
fibonacci(6) = 8
fibonacci(7) = 13
fibonacci(8) = 21
fibonacci(9) = 34
Cache info: CacheInfo(hits=8, misses=10, maxsize=128, currsize=10)
Cache hit rate: 0.80

How it works

The @lru_cache decorator wraps fibonacci so that results for each argument are stored in an internal dictionary. On subsequent calls with the same input, the cached value is returned instantly instead of recalculating. This turns the exponential recursion of naive Fibonacci into an almost linear approach. The decorator also exposes cache_info() to monitor hits, misses, and current cache size — useful for performance tuning. Because fibonacci is a pure function (same inputs always give the same outputs), the cache never causes stale results.

Common mistakes

  • Forgetting that decorated functions are cached — mutable default arguments or non-hashable inputs will raise TypeError.
  • Ignoring the global `maxsize` default of 128; if you expect more unique inputs, set a larger maxsize or use `maxsize=None` for unbounded caching.
  • Not using `cache_clear()` when the computation depends on external state that can change over time.

Variations

  1. Use `functools.cache` (Python 3.9+) as a simpler alias when you don't need a size limit.
  2. Use `@lru_cache(maxsize=None)` for unbounded memoization if memory is not a concern.

Real-world use cases

  • Speeding up recursive algorithms like the Fibonacci sequence or dynamic programming problems in coding interviews.
  • Caching results of expensive, deterministic API calls (e.g., parsing a large config file) so repeated requests don't hit the disk or network.
  • Memoizing hash computations or cryptographic signatures where identical inputs occur frequently in batch processing.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Concurrency & performance

Related tutorials and quizzes for this topic.