Memoizing decorator
Daishi Harada
daishi at gmail.com
Wed Dec 7 15:20:09 EST 2005
Hi Bengt,
Thanks for your reply.
>First, I would suggest thinking about the exact semantics of method
>memoization. E.g. suppose you write
>
> class Oops(object):
> def __init__(self, factor): self.factor = factor
> @memoize_fn
> def mul(self, x):
> return self.factor * x
>
>You would need a separate cache for every instance to use x as a cache lookup key,
>or look up with say (x, id(self)), either way assuming that self.factor can't change.
You're right; I wasn't thinking clearly enough.
I was in fact hoping to get the same memoize
to work with classmethods also.
I wonder if you wouldn't mind taking a look at
the following - it seems to "work" as given,
but I'm likely missing something again.
In particular, if one flips the order of the
'classmethod' and 'memoize_fn' decorators,
I get a 'classmethod not callable' error,
and I'm losing track of what's really going on.
(I've also "pushed" all of your logic into a
single descriptor class - am I forgetting
something by doing so?)
Thanks again and in advance for your
response,
Daishi
---
def test_memoize(memoize_fn):
def printsep():
print '-'*30
@memoize_fn
def fn(x):
print '(eval %s)' % str(x),
return x
print 'fn', fn(1); printsep()
print 'fn', fn(1); printsep()
class A(object):
n_insts = 0
def __init__(self, n):
self.n = n
A.n_insts += 1
@memoize_fn
def fn(self, x):
print '(eval %s %s)' % (str(self), str(x))
return x+self.n
# The following will memoize the wrong answer
# unless all instances are created first.
@classmethod
@memoize_fn
def clsfn(cls, x):
print '(clsmeth %s %s)' % (str(cls), str(x))
return x+cls.n_insts
def test_class(a):
print 'meth', a.fn(1); printsep()
print 'meth', a.fn(1); printsep()
print 'clsmeth', A.clsfn(1); printsep()
print 'clsmeth', A.clsfn(1); printsep()
a1 = A(1)
a2 = A(2)
test_class(a1)
test_class(a2)
class DescriptorMemoize(object):
def __init__(self, fn):
self.fn = fn
self._cache = {}
self._inst = None
def __get__(self, inst, owner):
print '__get__', inst, owner
self._inst = inst
return self
def __call__(self, *args):
if self._inst is not None:
args = (self._inst,)+args
try:
return self._cache[args]
except KeyError:
value = self.fn(*args)
self._cache[args] = value
return value
except TypeError:
return self.fn(*args)
More information about the Python-list
mailing list