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.

Medium Python 3.9+ Aug 9, 2026 Observability & SRE 13 views 0 copies

Python code

45 lines
Python 3.9+
import 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

stdout
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

  1. Use `functools.lru_cache` and overwrite `.cache_info()` for a quick hit-ratio in function decorators
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Observability & SRE

Related tutorials and quizzes for this topic.