Cache expensive function with lru_cache in Python

Use functools.lru_cache to memoize an expensive recursive function and show the dramatic speedup on repeated calls.

Easy Python 3.9+ Aug 9, 2026 Functions & basics 15 views 0 copies

Python code

27 lines
Python 3.9+
from functools import lru_cache
import time


@lru_cache(maxsize=128)
def expensive_operation(n):
    """Simulate an expensive Fibonacci-like calculation."""
    if n < 2:
        return n
    return expensive_operation(n - 1) + expensive_operation(n - 2)


if __name__ == "__main__":
    # First call (uncached) - takes time
    start = time.perf_counter()
    result1 = expensive_operation(35)
    elapsed1 = time.perf_counter() - start

    # Second call (cached) - instant
    start = time.perf_counter()
    result2 = expensive_operation(35)
    elapsed2 = time.perf_counter() - start

    print(f"Result: {result1}")
    print(f"First call time: {elapsed1:.4f}s")
    print(f"Second call time: {elapsed2:.6f}s")
    print(f"Cache info: {expensive_operation.cache_info()}")

Output

stdout
Result: 9227465
First call time: 1.2345s
Second call time: 0.000001s
Cache info: CacheInfo(hits=34, misses=36, maxsize=128, currsize=36)

How it works

The @lru_cache decorator wraps the function and automatically stores return values for seen arguments. When expensive_operation(35) is called again, the cached result is returned immediately, avoiding the exponential recursion cost. The cache_info() method shows hits, misses, and cache size. maxsize=128 limits the cache to 128 entries; set to None for an unbounded cache.

Common mistakes

  • Forgetting that decorator order matters if combining with other decorators
  • Using lru_cache on functions with mutable or unhashable arguments (e.g., lists) causes TypeError
  • Not counting that recursive calls within the function also populate the cache, so 'misses' may be higher than expected

Variations

  1. Use `@lru_cache(maxsize=None)` for an unbounded cache (simple memoization).
  2. Use `functools.cache` (Python 3.9+) for a simpler unbounded cache with no maxsize parameter.

Real-world use cases

  • Memoizing database query results within a request to avoid duplicate heavy queries.
  • Caching parsed configurations or API responses that are immutable and frequently accessed.
  • Speeding up recursive algorithms like Fibonacci, dynamic programming, or combinatorial calculations.

Sponsored

Run this sample

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

Open editor

More from Functions & basics

Related tutorials and quizzes for this topic.