Python lru_cache Explained: Memoization with functools
If a function receives the same inputs repeatedly, recalculating the answer is wasted work. Python's functools.lru_cache decorator remembers previous results and returns them instantly the next time the same arguments appear.
The basic example
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(40))
Without caching, recursive Fibonacci repeats the same branches exponentially. With lru_cache, each input is calculated once. The decorator stores a mapping from function arguments to return values.
What does LRU mean?
LRU means least recently used. By default, the cache has a limit. When it is full, Python removes the result that has not been used for the longest time. Set maxsize=None for an unbounded cache, but only when the input space is safely bounded or the process has enough memory.
@lru_cache(maxsize=128)
def exchange_rate(currency):
# expensive lookup or calculation
return load_rate(currency)
Use a small maxsize when there are many possible arguments and only recent values are useful.
Inspect and clear the cache
Every cached function exposes simple diagnostics:
print(exchange_rate.cache_info())
# CacheInfo(hits=10, misses=3, maxsize=128, currsize=3)
exchange_rate.cache_clear()
Hits show how often the cache saved work. Misses show how often the function still had to run. If hits are near zero, caching may not help—or the arguments may be changing every time.
Rules that surprise people
Arguments must be hashable, so lists and dictionaries cannot be used directly as cached arguments. Convert a list to a tuple or design the function around immutable inputs. The cache also treats some distinct argument combinations separately, so keep calls consistent.
Caching is process-local. It does not persist across restarts, and separate web workers have separate caches. Do not use it as a database or as a replacement for a shared cache such as Redis.
Avoid caching functions with side effects, random output, current-time reads, or results that depend on hidden global state. A cache assumes the same arguments produce the same answer.
When should you use lru_cache?
Use it for deterministic, relatively expensive functions with repeated inputs: recursive dynamic programming, parsing stable configuration, converting immutable values, and bounded lookup work. Measure before and after with cache_info(); a cache that never hits adds memory and lookup overhead without improving performance.
Try it: Run a Python lesson in your browser on PyRun and experiment with the cached and uncached Fibonacci versions without installing Python.