LRUCache backed by OrderedDict with stats

Python
"""Bounded LRU cache with hit and miss counters for quick profiling."""
from collections import OrderedDict
from typing import Any, Generic, TypeVar

K = TypeVar("K")
V = TypeVar("V")


class LRUCache(Generic[K, V]):
    """Hold at most capacity items and evict the least recently used key."""

    def __init__(self, capacity: int) -> None:
        if capacity < 1:
            raise ValueError("capacity must be at least 1")
        self.capacity = capacity
        self._items: OrderedDict[K, V] = OrderedDict()
        self.hits = 0
        self.misses = 0

    def get(self, key: K, default: Any = None) -> Any:
        """Return a cached value, refreshing recency, or default on a miss."""
        if key not in self._items:
            self.misses += 1
            return default
        self.hits += 1
        self._items.move_to_end(key)
        return self._items[key]

    def put(self, key: K, value: V) -> None:
        """Insert or update, evicting the least recently used entry if full."""
        if key in self._items:
            self._items.move_to_end(key)
        self._items[key] = value
        while len(self._items) > self.capacity:
            self._items.popitem(last=False)