Simple Redis Cache Helper in Python
Build a minimal Redis-backed cache with TTL, JSON serialization, and automated fetching to speed up repeated expensive lookups.
pip install redis
Python code
45 linesimport time
import redis
import json
class SimpleCache:
def __init__(self, host="localhost", port=6379, db=0, default_ttl=60):
self.client = redis.Redis(host=host, port=port, db=db, decode_responses=True)
self.default_ttl = default_ttl
def get(self, key):
value = self.client.get(key)
return json.loads(value) if value else None
def set(self, key, data, ttl=None):
self.client.set(key, json.dumps(data), ex=ttl or self.default_ttl)
def delete(self, key):
self.client.delete(key)
def fetch_with_cache(cache, key, expensive_function):
cached = cache.get(key)
if cached is not None:
print(f"Cache hit for '{key}'")
return cached
print(f"Cache miss for '{key}' — fetching fresh data")
data = expensive_function(key)
cache.set(key, data)
return data
def expensive_lookup(key):
time.sleep(1) # simulate slow work
return {"key": key, "result": f"data for {key}", "computed_at": time.time()}
if __name__ == "__main__":
cache = SimpleCache(default_ttl=5)
for _ in range(3):
result = fetch_with_cache(cache, "user:42", expensive_lookup)
print(result)
time.sleep(0.2)
cache.delete("user:42")
Output
Cache miss for 'user:42' — fetching fresh data
{'key': 'user:42', 'result': 'data for user:42', 'computed_at': 1700000000.123456}
Cache hit for 'user:42'
{'key': 'user:42', 'result': 'data for user:42', 'computed_at': 1700000000.123456}
Cache hit for 'user:42'
{'key': 'user:42', 'result': 'data for user:42', 'computed_at': 1700000000.123456}
How it works
The SimpleCache class wraps the Redis client with decode_responses=True to return strings instead of bytes. json.dumps serializes the Python dict into a JSON string before storing, and json.loads converts it back on retrieval. The ex parameter in set sets an expiration time, defaulting to self.default_ttl when no TTL is provided. fetch_with_cache checks the cache first, and only calls the expensive function on a miss, reducing repeated work. This pattern is cache-aside: the application manages the cache and refreshes it on a miss.
Common mistakes
- Forgetting `decode_responses=True`, causing `bytes` objects and errors when comparing strings.
- Not handling `None` from `get()`, which indicates a cache miss.
- Using a TTL that is too long, causing stale data in production.
- Not closing the Redis connection, though the client handles it gracefully on exit.
Variations
- Use `cache.set(key, data, ttl=30)` to override the default TTL for specific keys.
- Add a `get_or_set` method that combines fetch-with-cache into a single call.
Real-world use cases
- Caching database query results to reduce load on the primary database in a web application.
- Storing API responses in Redis to avoid hitting rate limits on external services.
- Sharing computed results across multiple app instances for faster startup and consistent data.
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.