Why is class decorator on method loosing self?
George Sakkis
george.sakkis at gmail.com
Tue Nov 21 14:04:23 EST 2006
c james wrote:
> I want to use the LRU decorator posted at
> http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/498110
> on a class method. However, it complains about missing arguments. The
> missing argument is `self`. I could use @classmethod but what I really
> need is an instance method. I don't see how and was hoping someone else
> might know the way.
>
> Here is an example with taking that recipe as lru.py
>
> import lru
>
> class Foo(object):
> def banner(self):
> print "Testing method"
>
> @memoize(3)
> def min_max(self, sequence):
> self.banner()
> return min(sequence), max(sequence)
>
> foo = Foo()
> print foo.min_max([9,7,5,3,1])
>
>
> Traceback (most recent call last):
> ...
> File "lru.py", line 48, in __call__
> value = self.func(*args, **kwargs)
> TypeError: min_max() takes exactly 2 arguments (1 given)
I don't think you can make it work without resorting to metaclass
magic. At the point of decoration min_max is still a function, not a
method, because class Foo has not been created yet. Here's a way to do
it with a custom metaclass; whether you really want to do it is a
different matter:
First off, remove the decoratorargs class and have memoize inherit from
object:
class memoize(object):
# class body stays the same
Then add the following:
# this is general enough to be moved to a separate module
class CustomizeMeta(type):
def __init__(cls, name, bases,dict):
for attr,val in dict.iteritems():
if hasattr(val, '__customize'):
setattr(cls, attr, getattr(val,'__customize')(cls))
def memoizefunction(*args, **kwds):
return lambda func: memoize(func, *args, **kwds)
def memoizemethod(*args, **kwds):
from types import MethodType
def wrapper(func):
func.__customize = lambda cls: \
MethodType(memoize(func,*args,**kwds), None, cls)
return func
return wrapper
#==== examples =============================================
@memoizefunction(3)
def fib(n):
return (n > 1) and (fib(n - 1) + fib(n - 2)) or 1
class Foo(object):
__metaclass__ = CustomizeMeta
def __init__(self, i): self._i = i
def banner(self):
print "Testing method"
@memoizemethod(3)
def min_max(self, sequence):
self.banner()
return min(sequence), max(sequence)
foo = Foo()
print foo.min_max([9,7,5,3,1])
George
More information about the Python-list
mailing list