On May 3, 7:21 pm, Andy Terrel <[EMAIL PROTECTED]> wrote: > Okay does anyone know how to decorate class member functions? > > The following code gives me an error: > > Traceback (most recent call last): > File "decorators2.py", line 33, in <module> > s.update() > File "decorators2.py", line 13, in __call__ > retval = self.fn.__call__(*args,**kws) > TypeError: update() takes exactly 1 argument (0 given) > > ------------------ > > #! /usr/bin/env python > > class Bugger (object): > def __init__ (self, module, fn): > self.module = module > self.fn = fn > > def __call__ (self,*args, **kws): > ret_val = self.fn(*args,**kws) > return ret_val > > def instrument (module_name): > ret_val = lambda x: Bugger(module_name, x) > return ret_val > > class Stupid: > def __init__(self): > self.val = 1 > > @instrument("xpd.spam") > def update(self): > self.val += 1 > > s = Stupid() > s.update()
As far as I can tell, the problem is that the decorator executes when the class is parsed, and at that time there is no self(the instance object). The decorator produces a callable Bugger object, but the callable object has no way to get self when s.update() is called. Normally when you call a class function, like s.update(), the __get__() method in the 'update' function object is called (all function objects have a __get__() method and therefore are descriptors). Then __get__() creates a method object out of the function object(update), and python automatically passes the instance object to the method object. However, the Bugger object does not have a __get__() method, so no method object is created when the Bugger object is called, and therefore self is not automatically passed to the Bugger object. The following solution adds a __get__() method to the Bugger object. Python automatically passes the instance object to the __get__() method, and the solution stores the instance in the Bugger object. Then __call__ is defined to send the instance object to update(). class Bugger (object): def __init__ (self, module, fn): self.module = module self.fn = fn def __call__ (self,*args, **kws): ret_val = self.fn(self.obj, *args,**kws) return ret_val def __get__(descr, inst, instCls=None): descr.obj = inst return descr def instrument (module_name): ret_val = lambda func: Bugger(module_name, func) return ret_val class Stupid(object): def __init__(self): self.val = 1 @instrument("xpd.spam") def update(self): self.val += 1 s = Stupid() s.update() s.update() s.update() print s.val --output:-- 4 -- http://mail.python.org/mailman/listinfo/python-list