Decorating class member functions

Peter Otten __peter__ at web.de
Fri May 4 00:34:06 EDT 2007


Andy Terrel 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()

The problem is not that you are decorating a method but that you are trying
to use a callable class instance as a method. For that to work the class
has to implement the descriptor protocol, see

http://users.rcn.com/python/download/Descriptor.htm

class Bugger (object):
    def __init__ (self, module, fn, instance=None):
        self.module = module
        self.fn = fn
        self.instance = instance

    def __call__ (self, *args, **kws):
        print "calling %s.%s()" % (self.module, self.fn.__name__)
        if self.instance is not None:
            args = (self.instance,) + args
        ret_val = self.fn(*args, **kws)
        return ret_val

    def __get__(self, instance, class_):
        if instance is None:
            return self
        return Bugger(self.module, self.fn, instance)

def instrument (module_name):
    ret_val = lambda x: Bugger(module_name, x)
    return ret_val

class Stupid(object):
    @instrument("xpd.spam")
    def update(self):
        print "update()"

s = Stupid()
s.update()
Stupid.update(s)

Peter



More information about the Python-list mailing list