Expiring Dict
expiring-dict is a Python library that provides a dictionary-like object with Time-To-Live (TTL) support for its values, enabling automatic expiration of cached items. It is designed for simple caching scenarios where items need to be removed after a certain period. The library is currently active, with its latest version released in February 2025, and offers both dictionary-level and key-level expiration settings.
Common errors
-
KeyError: 'some_key'
cause Attempting to access an expired key using `cache['key']` instead of `cache.get('key')`. When a key expires, it's effectively removed, so direct access will raise a KeyError.fixAlways use `value = cache.get('key')` to safely retrieve values. This method returns `None` (or a specified default) if the key does not exist or has expired, preventing a `KeyError`. -
TypeError: cannot pickle '_thread.lock' object
cause You are attempting to serialize an `ExpiringDict` instance using a module like `pickle` or `dill`. `ExpiringDict` uses internal threading locks for thread-safety, which are generally not picklable.fixDo not attempt to pickle `ExpiringDict` objects directly. If you need to persist the cached data, extract the key-value pairs (and their timestamps if needed) into a standard dictionary or list of tuples, then pickle that data. Reconstruct the `ExpiringDict` from this data upon deserialization.
Warnings
- gotcha Iteration (e.g., `for key in cache` or `cache.keys()`) and checking length (`len(cache)`) do not automatically remove expired items. Expiration only occurs when an item is accessed (e.g., `cache['key']` or `cache.get('key')`). This can lead to seemingly 'stale' or inaccurate views of the dictionary content if not handled explicitly.
- gotcha ExpiringDict objects may not be reliably picklable due to internal threading locks used for thread safety. Attempting to pickle an ExpiringDict can result in a `TypeError` related to unpicklable lock objects, making it difficult to serialize and deserialize the cache.
- gotcha Setting `max_age_seconds` for the `ExpiringDict` applies to *all* keys in the dictionary by default. If you intend for some keys to have no expiration or a different expiration, you must explicitly use the `cache.ttl(key, value, age)` method or ensure `max_age_seconds` is `None` during initialization if you only want key-level TTLs.
Install
-
pip install expiring-dict
Imports
- ExpiringDict
from expiring_dict import ExpiringDict
Quickstart
from expiring_dict import ExpiringDict
import time
# Dictionary-level TTL: items expire after 1 second
cache_dict_level = ExpiringDict(max_age_seconds=1)
cache_dict_level["my_key"] = "my_value"
print(f"Initial value (dict-level): {cache_dict_level.get('my_key')}")
time.sleep(1.5)
print(f"Value after 1.5 seconds (dict-level): {cache_dict_level.get('my_key')}") # Should be None
# Key-level TTL: individual keys expire after specified seconds
cache_key_level = ExpiringDict()
cache_key_level["persistent_key"] = "this never expires by default"
cache_key_level.ttl("expiring_key", "this expires in 1 second", 1)
print(f"\nPersistent value: {cache_key_level.get('persistent_key')}")
print(f"Expiring value (initial): {cache_key_level.get('expiring_key')}")
time.sleep(1.5)
print(f"Persistent value (after 1.5s): {cache_key_level.get('persistent_key')}")
print(f"Expiring value (after 1.5s): {cache_key_level.get('expiring_key')}") # Should be None