Caching & Memoization
Caching stores computed results for reuse. functools.lru_cache handles in-process memoization; Redis/Memcached handle shared caches across processes.
Search across all documentation pages
Caching stores computed results for reuse. functools.lru_cache handles in-process memoization; Redis/Memcached handle shared caches across processes.
from functools import lru_cache
@lru_cache(maxsize=128)
def expensive_lookup(key: str) -> dict:
return fetch_from_database(key)When to reach for this:
from functools import lru_cache
import httpx
@lru_cache(maxsize=256)
def get_exchange_rate(currency: str) -> float:
response = httpx.get(f"https://api.example/rates/{currency}")
response.raise_for_status()
return response.json()["rate"]
# First call: HTTP request
# Subsequent calls: cached
rate1 = get_exchange_rate("EUR")
rate2 = get_exchange_rate("EUR") # cache hit
print(get_exchange_rate.cache_info())
# CacheInfo(hits=1, misses=1, maxsize=256, currsize=1)# TTL cache with cachetools
from cachetools import TTLCache, cached
cache = TTLCache(maxsize=100, ttl=300)
@cached(cache)
def get_user(user_id: int) -> dict:
return db.query(user_id)What this demonstrates:
lru_cache for unbounded-reuse pure functionscache_info() monitors hit rate| Layer | Tool | Scope |
|---|---|---|
| In-process | lru_cache, cachetools | Single process |
| Shared | Redis, Memcached | All app instances |
| HTTP | CDN, Cache-Control | Client and edge |
| Framework | FastAPI @lru_cache on deps | Per-worker |
get_exchange_rate.cache_clear() # manual invalidationmaxsize.| Alternative | Use When | Don't Use When |
|---|---|---|
| Eager precomputation | Data changes rarely | Dynamic inputs |
| Database query cache | ORM-level | Application-level control needed |
| No cache | Data always fresh | Repeated expensive lookups |
lru_cache for single-process, pure functions. Redis for multi-instance shared cache.
async_lru package or manual dict with asyncio lock.
Start 128-256. Monitor cache_info() hit rate; adjust.
@lru_cache on dependency functions. HTTP caching with Cache-Control headers for clients.
Use lock per key or stale-while-revalidate pattern for popular keys.
Yes but cache is per-method, not per-instance. Consider functools on standalone function.
func.cache_clear() in test teardown. Or mock the underlying data source.
django.core.cache with Redis backend. @cache_page for view caching.
Financial transactions, real-time data, security-sensitive per-user data without key isolation.
cache_info() for lru_cache. Redis INFO stats for shared caches.
Stack versions: This page was written for Python 3.14.0, FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026