Update memoize class and add support for persistent cache

This commit is contained in:
Kim Silkebækken 2013-01-11 12:18:17 +01:00
parent bba272e0bd
commit 7eb3bfde9c
1 changed files with 42 additions and 34 deletions

View File

@ -1,48 +1,56 @@
# -*- coding: utf-8 -*-
import cPickle as pickle
import functools
import os
import tempfile
import time
class memoize(object):
'''Memoization decorator with timout.
http://code.activestate.com/recipes/325905-memoize-decorator-with-timeout/
'''Memoization decorator with timeout.
'''
_caches = {}
_timeouts = {}
_cache = {}
def __init__(self, timeout, additional_key=None):
def __init__(self, timeout, additional_key=None, persistent=False, persistent_file=None):
self.timeout = timeout
self.additional_key = additional_key
self.persistent = persistent
self.persistent_file = persistent_file or os.path.join(tempfile.gettempdir(), 'powerline-cache')
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()
def __call__(self, func):
@functools.wraps(func)
def decorated_function(*args, **kwargs):
if self.additional_key:
key = (args, tuple(kw), self.additional_key())
key = (func.__name__, args, tuple(kwargs.items()), self.additional_key())
else:
key = (args, tuple(kw))
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
key = (func.__name__, args, tuple(kwargs.items()))
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