Decorating class member functions
7stud
bbxx789_05ss at yahoo.com
Fri May 4 01:36:59 EDT 2007
On May 3, 7:21 pm, Andy Terrel <andy.ter... at gmail.com> 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
More information about the Python-list
mailing list