Is there a pythonic way to support keyword arguments for a memoize decorator in Python?
I'd suggest something like the following:
import inspect
class key_memoized(object):
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args, **kwargs):
key = self.key(args, kwargs)
if key not in self.cache:
self.cache[key] = self.func(*args, **kwargs)
return self.cache[key]
def normalize_args(self, args, kwargs):
spec = inspect.getargs(self.func.__code__).args
return dict(kwargs.items() + zip(spec, args))
def key(self, args, kwargs):
a = self.normalize_args(args, kwargs)
return tuple(sorted(a.items()))
Example:
@key_memoized
def foo(bar, baz, spam):
print 'calling foo: bar=%r baz=%r spam=%r' % (bar, baz, spam)
return bar + baz + spam
print foo(1, 2, 3)
print foo(1, 2, spam=3) #memoized
print foo(spam=3, baz=2, bar=1) #memoized
Note that you can also extend key_memoized
and override its key()
method to provide more specific memoization strategies, e.g. to ignore some of the arguments:
class memoize_by_bar(key_memoized):
def key(self, args, kwargs):
return self.normalize_args(args, kwargs)['bar']
@memoize_by_bar
def foo(bar, baz, spam):
print 'calling foo: bar=%r baz=%r spam=%r' % (bar, baz, spam)
return bar
print foo('x', 'ignore1', 'ignore2')
print foo('x', 'ignore3', 'ignore4')
Try lru_cache:
@functools.lru_cache(maxsize=128, typed=False)
Decorator to wrap a function with a memoizing callable that saves up to the maxsize most recent calls. It can save time when an expensive or I/O bound function is periodically called with the same arguments.
lru_cache added in python 3.2, but can be backported into 2.x