How to Build a TTL Cache Dict in Python
Create a dictionary subclass that automatically expires keys after a fixed time-to-live using timestamps.
Python code
44 linesimport time
class TTLDict(dict):
def __init__(self, ttl, *args, **kwargs):
self.ttl = ttl
self._expires = {}
super().__init__(*args, **kwargs)
def __setitem__(self, key, value):
super().__setitem__(key, value)
self._expires[key] = time.time() + self.ttl
def __getitem__(self, key):
if self._is_expired(key):
self._delete_expired(key)
raise KeyError(key)
return super().__getitem__(key)
def __contains__(self, key):
if self._is_expired(key):
self._delete_expired(key)
return False
return super().__contains__(key)
def get(self, key, default=None):
try:
return self[key]
except KeyError:
return default
def _is_expired(self, key):
return key in self._expires and time.time() > self._expires[key]
def _delete_expired(self, key):
del dict.__getitem__(self, key)
del dict.__getattribute__(self, '_expires')[key]
if __name__ == "__main__":
cache = TTLDict(2)
cache["name"] = "Alice"
print(f"immediate: {cache.get('name')}")
time.sleep(3)
print(f"after 3s: {cache.get('name')}")
print(f"in dict: {'name' in cache}")
Output
immediate: Alice
after 3s: None
in dict: False
How it works
The TTLDict class extends the built-in dict and tracks expiration times in a separate _expires map. On every __setitem__, it stores a timestamp equal to now + ttl; lookups and membership checks call _is_expired and purge stale entries. The overridden get returns a default instead of raising KeyError when a key has expired, which keeps callers safe. Because dict is written in C, the class must super().__getattribute__ to reach _expires in deletion logic — a subtle but important detail.
Common mistakes
- Using `self._expires` inside `__getattribute__` or `__delitem__` causes infinite recursion when the attribute isn't initialized.
- Forgetting to handle expired keys in `__contains__`, leaving stale data visible to `if key in cache` checks.
- Not clearing `_expires` after `pop` or `del`, leaking memory over time.
Variations
- Use `collections.OrderedDict` to evict oldest entries before TTL expires.
- Implement a background thread that periodically purges expired keys instead of lazily checking on access.
Real-world use cases
- Caching database query results for a short period to reduce load in a web service.
- Storing session tokens or API keys that must be invalidated after a timeout.
- Temporarily memoizing expensive function results in data pipelines.
Sponsored
More from Dictionaries & sets
- Build a Case-Insensitive Dict with a Wrapper Class in Python medium
- Build a defaultdict histogram of categories in Python easy
- Build adjacency dict graph from edges in Python easy
- Build an OrderedDict insertion order demo in Python 3 easy
- Check Invertible Mapping for Duplicate Values in Python easy
- Compare Two Dictionaries in Python easy
Keep learning
Related tutorials and quizzes for this topic.