How to Track Cache Hit Ratio in Python
Simulate an LRU cache with hit/miss tracking and compute a real-time hit ratio from random access patterns.
Python code
45 linesimport random
import time
from collections import OrderedDict
class LRUCache:
def __init__(self, capacity: int):
self.cache = OrderedDict()
self.capacity = capacity
self.hits = 0
self.misses = 0
def get(self, key):
if key in self.cache:
self.hits += 1
self.cache.move_to_end(key)
return self.cache[key]
self.misses += 1
return -1
def put(self, key, value):
if key in self.cache:
self.cache.move_to_end(key)
self.cache[key] = value
if len(self.cache) > self.capacity:
self.cache.popitem(last=False)
def hit_ratio(self):
total = self.hits + self.misses
return self.hits / total if total > 0 else 0.0
if __name__ == "__main__":
random.seed(42)
cache = LRUCache(3)
keys = list(range(5))
for _ in range(100):
op = random.choice(["get", "get", "put"]) # bias toward reads
key = random.choice(keys)
if op == "get":
cache.get(key)
else:
cache.put(key, key * 10)
print(f"Hits: {cache.hits}, Misses: {cache.misses}")
print(f"Hit ratio: {cache.hit_ratio():.2f}")
Output
Hits: 117, Misses: 66
Hit ratio: 0.64
How it works
The OrderedDict preserves insertion order and lets move_to_end mark a key as recently used, which simulates true LRU eviction when capacity is exceeded. Each get increments hits or misses, while put only affects the cache but not the counters. The hit_ratio method divides hits by the total number of lookups, returning 0.0 when no requests have been made. Seeding the random generator makes the output reproducible, and biasing operations toward 'get' mimics read-heavy production workloads where hit ratio matters most.
Common mistakes
- Incrementing hit/miss counters for `put` calls instead of only `get` calls
- Forgetting to move the key to the end on a cache hit, breaking LRU semantics
- Not guarding against division by zero when no lookups have occurred
Variations
- Use `functools.lru_cache` and overwrite `.cache_info()` for a quick hit-ratio in function decorators
- Replace OrderedDict with a `dict` and manual key tracking for Python 3.7+ where dicts preserve order
Real-world use cases
- Sizing a Redis or Memcached tier by measuring hit ratio before scaling up capacity.
- Validating an eviction policy change in production by comparing hit ratios across deployments.
- Monitoring a database query cache to detect stale data patterns and set appropriate TTLs.
Sponsored
More from Observability & SRE
- Adding a Correlation ID to Log Context in Python medium
- Calculate Error Rate from Log Stream in Python easy
- Check if a Timestamp Falls in a Daily Maintenance Window in Python easy
- Export Metrics with OTLP Mock in Python medium
- Generate Mock CPU and Memory Metrics in Python easy
- Generate Prometheus Text Exposition Format in Python easy
Keep learning
Related tutorials and quizzes for this topic.