How to Cache Function Results with Redis in Python
A RedisCache helper class caches function results using a decorator, with JSON serialization and TTL-based expiry.
Requires third-party packages — install first
pip install redis
Python code
36 linesimport redis
import json
from functools import wraps
class RedisCache:
def __init__(self, host='localhost', port=6379, db=0, ttl=60):
self.client = redis.Redis(host=host, port=port, db=db, decode_responses=True)
self.ttl = ttl
def cached(self, key_prefix):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
key = f"{key_prefix}:{args}:{kwargs}"
cached_value = self.client.get(key)
if cached_value is not None:
print(f"Cache HIT for {key}")
return json.loads(cached_value)
print(f"Cache MISS for {key}")
result = func(*args, **kwargs)
self.client.setex(key, self.ttl, json.dumps(result))
return result
return wrapper
return decorator
cache = RedisCache(ttl=10)
@cache.cached("user")
def get_user(user_id):
return {"id": user_id, "name": "Alice", "age": 30}
if __name__ == "__main__":
print(get_user(1))
print(get_user(1))
Output
Cache MISS for user:(1,):{}
{'id': 1, 'name': 'Alice', 'age': 30}
Cache HIT for user:(1,):{}
{'id': 1, 'name': 'Alice', 'age': 30}
How it works
The decorator cached wraps a function, computing a cache key from arguments. On a miss, it runs the function and stores the JSON result with setex, setting a TTL. On a hit, it reads the cached string and returns it with json.loads. Using functools.wraps preserves the original function metadata.
Common mistakes
- Forgetting to set `decode_responses=True` so values are strings, not bytes.
- Not including kwargs in the cache key, causing different calls to collide.
- Using `json.dumps` without `ensure_ascii=False` when caching non-ASCII strings.
- Assuming cache invalidation is automatic; TTL only expires old data
Variations
- Use a hash of arguments (e.g., `hashlib.md5`) to shorten cache keys.
- Add an optional `cache_none` flag to cache `None` results as well.
Real-world use cases
- Caching database query results to reduce load on the primary instance.
- Storing API responses for rate-limited external services to save quota.
- Memoizing expensive computations like image processing in a web server.
Sponsored
More from Caching & Redis
- Cache Asides in Python with a Read-Through Loader easy
- Cache Data in Redis with Python easy
- Cache Penetration Null Object Mock in Python medium
- Cache Stampede Prevention with SingleFlight in Python medium
- Cache Warming with Python: Preload Hot Keys easy
- Coalescing duplicate in-flight requests: one shared result for concurrent callers hard
Keep learning
Related tutorials and quizzes for this topic.