This simple decorator is different to other memoize decorators in that it will only cache results for a period of time. It also provides a simple method of cleaning the cache of old entries via the .collect method. This will help prevent excessive or needless memory consumption.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | class MWT(object):
"""Memoize With Timeout"""
_caches = {}
_timeouts = {}
def __init__(self,timeout=2):
self.timeout = timeout
def collect(self):
"""Clear cache of results which have timed out"""
for func in self._caches:
cache = {}
for key in self._caches[func]:
if (time.time() - self._caches[func][key][1]) < self._timeouts[func]:
cache[key] = self._caches[func][key]
self._caches[func] = cache
def __call__(self, f):
self.cache = self._caches[f] = {}
self._timeouts[f] = self.timeout
def func(*args, **kwargs):
kw = kwargs.items()
kw.sort()
key = (args, tuple(kw))
try:
v = self.cache[key]
print "cache"
if (time.time() - v[1]) > self.timeout:
raise KeyError
except KeyError:
print "new"
v = self.cache[key] = f(*args,**kwargs),time.time()
return v[0]
func.func_name = f.func_name
return func
#The code below demonstrates usage of the MWT decorator. Notice how the cache is
#cleared of some entries after the MWT().collect() method is called.
@MWT()
def z(a,b):
return a + b
@MWT(timeout=5)
def x(a,b):
return a + b
z(1,2)
x(1,3)
print MWT()._caches
#>>> {<function 'z'>: {(1, 2): (3, 1099276281.092)},<function 'x'> : {(1, 3): (4, 1099276281.092)}}
time.sleep(3)
MWT().collect()
print MWT()._caches
#>>> {<function 'z'>: {},<function 'x'> : {(1, 3): (4, 1099276281.092)}}
|
Tags: algorithms
Here's a version that works with Python 3 and adds the missing "import time".