Introduction
Memoization is an optimization technique that caches function results. Python provides built-in decorators like @lru_cache and @cache for easy memoization.
lru_cache
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(100)) # Fast due to caching
print(fibonacci.cache_info()) # CacheInfo(hits=..., misses=...)
Cache Decorator
from functools import cache
@cache
def expensive_computation(n):
result = n ** 2
return result
# Unlimited cache (Python 3.9+)
result = expensive_computation(100)
print(expensive_computation.cache_info())
Custom Cache
from functools import lru_cache
from typing import Any, Dict
import hashlib
import pickle
def memoize(func):
cache: Dict[str, Any] = {}
def wrapper(*args, **kwargs):
key = hashlib.sha256(
pickle.dumps((args, sorted(kwargs.items())))
).hexdigest()
if key not in cache:
cache[key] = func(*args, **kwargs)
return cache[key]
wrapper.cache_clear = lambda: cache.clear()
return wrapper
@memoize
def complex_calculation(x, y):
return x ** y + x * y
Cache with TTL
import time
from functools import wraps
def timed_cache(ttl_seconds: int):
cache = {}
def decorator(func):
@wraps(func)
def wrapper(*args):
key = str(args)
now = time.time()
if key in cache:
result, timestamp = cache[key]
if now - timestamp < ttl_seconds:
return result
result = func(*args)
cache[key] = (result, now)
return result
wrapper.cache_clear = lambda: cache.clear()
return wrapper
return decorator
@timed_cache(ttl_seconds=60)
def get_data(query):
return f"Result for: {query}"
Caching Class Methods
from functools import lru_cache
class DataProcessor:
@lru_cache(maxsize=10)
def process(self, item):
return f"Processed: {item}"
def cache_clear(self):
self.process.cache_clear()
Practice Problems
- Use lru_cache for recursive function
- Create custom memoization decorator
- Implement cache with expiration
- Cache class method results
- Compare cache performance