Update memoize class and add support for persistent cache
This commit is contained in:
parent
bba272e0bd
commit
7eb3bfde9c
|
@ -1,48 +1,56 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import cPickle as pickle
|
||||||
|
import functools
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
class memoize(object):
|
class memoize(object):
|
||||||
'''Memoization decorator with timout.
|
'''Memoization decorator with timeout.
|
||||||
|
|
||||||
http://code.activestate.com/recipes/325905-memoize-decorator-with-timeout/
|
|
||||||
'''
|
'''
|
||||||
_caches = {}
|
_cache = {}
|
||||||
_timeouts = {}
|
|
||||||
|
|
||||||
def __init__(self, timeout, additional_key=None):
|
def __init__(self, timeout, additional_key=None, persistent=False, persistent_file=None):
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
self.additional_key = additional_key
|
self.additional_key = additional_key
|
||||||
|
self.persistent = persistent
|
||||||
|
self.persistent_file = persistent_file or os.path.join(tempfile.gettempdir(), 'powerline-cache')
|
||||||
|
|
||||||
def collect(self):
|
def __call__(self, func):
|
||||||
'''Clear cache of results which have timed out.
|
@functools.wraps(func)
|
||||||
'''
|
def decorated_function(*args, **kwargs):
|
||||||
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()
|
|
||||||
if self.additional_key:
|
if self.additional_key:
|
||||||
key = (args, tuple(kw), self.additional_key())
|
key = (func.__name__, args, tuple(kwargs.items()), self.additional_key())
|
||||||
else:
|
else:
|
||||||
key = (args, tuple(kw))
|
key = (func.__name__, args, tuple(kwargs.items()))
|
||||||
try:
|
|
||||||
v = self.cache[key]
|
|
||||||
if (time.time() - v[1]) > self.timeout:
|
|
||||||
raise KeyError
|
|
||||||
except KeyError:
|
|
||||||
v = self.cache[key] = f(*args, **kwargs), time.time()
|
|
||||||
return v[0]
|
|
||||||
func.func_name = f.func_name
|
|
||||||
|
|
||||||
return func
|
if self.persistent:
|
||||||
|
try:
|
||||||
|
with open(self.persistent_file, 'rb') as fileobj:
|
||||||
|
self._cache = pickle.load(fileobj)
|
||||||
|
except (IOError, EOFError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
cached = self._cache.get(key, None)
|
||||||
|
|
||||||
|
if cached is None or time.time() - cached['time'] > self.timeout:
|
||||||
|
cached = self._cache[key] = {
|
||||||
|
'result': func(*args, **kwargs),
|
||||||
|
'time': time.time(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.persistent:
|
||||||
|
try:
|
||||||
|
with open(self.persistent_file, 'wb') as fileobj:
|
||||||
|
pickle.dump(self._cache, fileobj)
|
||||||
|
except IOError:
|
||||||
|
# Unable to write to file
|
||||||
|
pass
|
||||||
|
except TypeError:
|
||||||
|
# Unable to pickle function result
|
||||||
|
pass
|
||||||
|
|
||||||
|
return cached['result']
|
||||||
|
return decorated_function
|
||||||
|
|
Loading…
Reference in New Issue