MediumCachingPython 3
LRU TTL Cache
Combine recency ordering and TTL cleanup without corrupting cache invariants.
35m3 sample tests8 hidden tests
Implement a bounded cache with least-recently-used (LRU) eviction and optional time-to-live (TTL) expiry. Recency chooses among live entries; an expired TTL deadline always takes priority.
Requirements
- Define
LRUTTLCache(capacity, now). put(key, value, ttl=None)stores a value. For an existing live key, overwrite the value, move it to most recently used, and replace its TTL fromnow()(ttl=Nonemeans no expiry).get(key)returns the value orNonewhen missing or expired.getmarks a key as most recently used.- When capacity is exceeded, evict expired entries first, then least recently used entries. Cleanup of expired keys must happen on
putwhen reclaiming capacity, independent of any earliergetfor the expired key. - Expiry is inclusive: a key is expired when
now() >= expires_at. - A non-positive capacity stores no entries. A non-positive TTL expires immediately.
Example
This trace makes a most recently used, evicts b, then advances the injected clock to a's inclusive expiry boundary.
python
clock = {"now": 0.0}
cache = LRUTTLCache(capacity=2, now=lambda: clock["now"])
cache.put("a", 1, ttl=5)
cache.put("b", 2)
assert cache.get("a") == 1
cache.put("c", 3)
assert cache.get("b") is None
clock["now"] = 5.0
assert cache.get("a") is NoneConstraints
- Use standard-library Python only.
- Don't use
functools.lru_cache. capacityis an integer. Keys are strings; values may be any Python object. A storedNoneis indistinguishable from a miss through this API.- Calls are serialized.
now()returns finite, nondecreasing seconds; TTLs are finite seconds orNone. A successful read changes recency but never extends the deadline. - Writing an expired key creates a fresh entry. Writing a non-positive TTL over a live key invalidates its old value immediately and must not evict another live key to retain the expired replacement.
Editor