Python in-memory cache with time to live
In case you don't want to use any 3rd libraries, you can add one more parameter to your expensive function: ttl_hash=None
. This new parameter is so-called "time sensitive hash", its the only purpose is to affect lru_cache
.
For example:
from functools import lru_cache
import time
@lru_cache()
def my_expensive_function(a, b, ttl_hash=None):
del ttl_hash # to emphasize we don't use it and to shut pylint up
return a + b # horrible CPU load...
def get_ttl_hash(seconds=3600):
"""Return the same value withing `seconds` time period"""
return round(time.time() / seconds)
# somewhere in your code...
res = my_expensive_function(2, 2, ttl_hash=get_ttl_hash())
# cache will be updated once in an hour
The OP is using python 2.7 but if you're using python 3, ExpiringDict
mentioned in the accepted answer is currently, well, expired. The last commit to the github repo was June 17, 2017 and there is an open issue that it doesn't work with Python 3.5
As of September 1, 2020, there is a more recently maintained project cachetools.
pip install cachetools
from cachetools import TTLCache
cache = TTLCache(maxsize=10, ttl=360)
cache['apple'] = 'top dog'
...
>>> cache['apple']
'top dog'
... after 360 seconds...
>>> cache['apple']
KeyError exception raised
ttl
is the time to live in seconds.
Regarding an expiring in-memory cache, for general purpose use, a common design pattern to typically do this is not via a dictionary, but via a function or method decorator. A cache dictionary is managed behind the scenes. As such, this answer somewhat complements the answer by User which uses a dictionary rather than a decorator.
The ttl_cache
decorator in cachetools
works a lot like functools.lru_cache
, but with a time to live.
import cachetools.func
@cachetools.func.ttl_cache(maxsize=128, ttl=10 * 60)
def example_function(key):
return get_expensively_computed_value(key)
class ExampleClass:
EXP = 2
@classmethod
@cachetools.func.ttl_cache()
def example_classmethod(cls, i):
return i * cls.EXP
@staticmethod
@cachetools.func.ttl_cache()
def example_staticmethod(i):
return i * 3
You can use the expiringdict
module:
The core of the library is
ExpiringDict
class which is an ordered dictionary with auto-expiring values for caching purposes.
In the description they do not talk about multithreading, so in order not to mess up, use a Lock
.