When creating decorators for use on class methods, I'm having trouble when the decorator mechanism is a class rather than a function/closure. When the class form is used, my decorator doesn't get treated as a bound method.
Generally I prefer to use the function form for decorators but in this case I have to use an existing class to implement what I need.
This seems as though it might be related to python-decorator-makes-function-forget-that-it-belongs-to-a-class but why does it work just fine for the function form?
Here is the simplest example I could make to show all goings on. Sorry about the amount of code:
def decorator1(dec_param):def decorator(function):print 'decorator1 decoratoring:', functiondef wrapper(*args):print 'wrapper(%s) dec_param=%s' % (args, dec_param)function(*args)return wrapperreturn decoratorclass WrapperClass(object):def __init__(self, function, dec_param):print 'WrapperClass.__init__ function=%s dec_param=%s' % (function, dec_param)self.function = functionself.dec_param = dec_paramdef __call__(self, *args):print 'WrapperClass.__call__(%s, %s) dec_param=%s' % (self, args, self.dec_param)self.function(*args)def decorator2(dec_param):def decorator(function):print 'decorator2 decoratoring:', functionreturn WrapperClass(function, dec_param)return decoratorclass Test(object):@decorator1(dec_param=123)def member1(self, value=1):print 'Test.member1(%s, %s)' % (self, value)@decorator2(dec_param=456)def member2(self, value=2):print 'Test.member2(%s, %s)' % (self, value)@decorator1(dec_param=123)
def free1(value=1):print 'free1(%s)' % (value)@decorator2(dec_param=456)
def free2(value=2):print 'free2(%s)' % (value)test = Test()
print '\n====member1===='
test.member1(11)print '\n====member2===='
test.member2(22)print '\n====free1===='
free1(11)print '\n====free2===='
free2(22)
Output:
decorator1 decoratoring: <function member1 at 0x3aba30>
decorator2 decoratoring: <function member2 at 0x3ab8b0>
WrapperClass.__init__ function=<function member2 at 0x3ab8b0> dec_param=456
decorator1 decoratoring: <function free1 at 0x3ab9f0>
decorator2 decoratoring: <function free2 at 0x3ab970>
WrapperClass.__init__ function=<function free2 at 0x3ab970> dec_param=456====member1====
wrapper((<__main__.Test object at 0x3af5f0>, 11)) dec_param=123
Test.member1(<__main__.Test object at 0x3af5f0>, 11)====member2====
WrapperClass.__call__(<__main__.WrapperClass object at 0x3af590>, (22,)) dec_param=456
Test.member2(22, 2) <<<- Badness HERE!====free1====
wrapper((11,)) dec_param=123
free1(11)====free2====
WrapperClass.__call__(<__main__.WrapperClass object at 0x3af630>, (22,)) dec_param=456
free2(22)