Cache a pure Fibonacci helper with lru_cache
Also published in our Blogger archive.
Cache a pure Fibonacci helper with lru_cache
Recursive Fibonacci is a compact illustration of overlapping work: calculating fibonacci(10) repeatedly needs values such as fibonacci(8) and fibonacci(7). Decorating the helper with functools.lru_cache(maxsize=64) stores results by argument. The first call returns 55; the second returns the same integer from the existing entry instead of expanding the recursive tree again.
The example clears the cache first so its checks describe this run. Computing values zero through ten creates eleven cached entries, and the second top-level call increases the hit count. cache_info() is useful for observing those counters and the current size without exposing the cached values themselves.
Caching suits this function because its result depends only on its integer argument and it creates no observable side effect. It is a poor fit for a function that reads a clock, a changing file, random state, or a remote service: replaying an old result could be incorrect. Cache keys must be hashable; this helper deliberately rejects booleans and non-integers. A bounded cache also means old entries can be evicted, so caching is an optimization rather than a promise that every prior result remains available.
AI assistance disclosure: This article was prepared with AI assistance.
Example
from functools import lru_cache
@lru_cache(maxsize=64)
def fibonacci(n):
if type(n) is not int:
raise TypeError("n must be an integer")
if n < 0:
raise ValueError("n must be non-negative")
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
fibonacci.cache_clear()
first = fibonacci(10)
before = fibonacci.cache_info()
second = fibonacci(10)
after = fibonacci.cache_info()
assert first == second == 55
assert before.misses == 11
assert after.hits == before.hits + 1
assert after.currsize == 11
print(first)
print(second)
Expected output
55
55