By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,767 Members | 2,114 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,767 IT Pros & Developers. It's quick & easy.

Why is class decorator on method loosing self?

P: n/a
I want to use the LRU decorator posted at
http://aspn.activestate.com/ASPN/Coo.../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)

Nov 21 '06 #1
Share this Question
Share on Google+
4 Replies


P: n/a
c james wrote:
I want to use the LRU decorator posted at
http://aspn.activestate.com/ASPN/Coo.../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

Nov 21 '06 #2

P: n/a
If I am reading this correctly you, are rebinding min_max in
CustomizeMeta using '__customize' as the attribute to identify the
member to work on.

Thank you. I think you are right, this is probably the best way to
implement what I intend for caching resource intensive processing.

to George Sakkis wrote:
>
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:
George
Nov 21 '06 #3

P: n/a
George Sakkis wrote:
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:
An improvement to my previous hack: leave memoize as is in the cookbook
(extending decoratorargs) and add two lines to decoratorargs:

# This would usually be defined elsewhere
class decoratorargs(object):
def __new__(typ, *attr_args, **attr_kwargs):
def decorator(orig_func):
self = object.__new__(typ)
self.__init__(orig_func, *attr_args, **attr_kwargs)
if callable(self):
self._customize = lambda cls: MethodType(self, None,
cls)
return self
return decorator

Now you don't need memoizefunction and memoizemethod, but you still
need the customized metaclass (changed __customize to _customize; name
turns to a PITA sooner or later):

class CustomizeMeta(type):
def __init__(cls, name, bases,dict):
for attr,val in dict.iteritems():
if hasattr(val, '_customize'):
setattr(cls, attr, val._customize(cls))
#==== examples =============================================

@memoize(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"

@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])
George

Nov 21 '06 #4

P: n/a
George Sakkis wrote:
Now you don't need memoizefunction and memoizemethod, but you still
need the customized metaclass (changed __customize to _customize; name
turns to a PITA sooner or later):
There was supposed to be a "mangling" after "name" (see, it's hard to
even spell it out correctly, let alone use it <wink>).

George

Nov 21 '06 #5

This discussion thread is closed

Replies have been disabled for this discussion.