Decorating methods - where do my arguments go?

Duncan Booth duncan.booth at invalid.invalid
Tue May 12 04:25:59 EDT 2009

Michele Simionato <michele.simionato at> wrote:

> On May 12, 8:54 am, Mikael Olofsson <mik... at> wrote:
>> Peter Otten wrote:
>> > I usually use decorator functions, but I think the following should
>> > wor 
> k,
>> > too:
>> > class deco(object):
>> >     def __init__(self, func):
>> >         self._func = func
>> >     def __call__(self, *args):
>> >         print "Decorator:", args
>> >         self._func(*args)
>> >     def __get__(self, *args):
>> >         return deco(self._func.__get__(*args))
>> This looks like a winner to me. It is elegant, works for functions as
>> well as for methods, and does not mess with the internals of the
>> decorator which avoids the problems that Duncan pointed out.
> Still it turns something which is a function into an object and you
> lose the
> docstring and the signature. pydoc will not be too happy with this
> approach.

Also it means every time the decorator is invoked 'self' references a 
new instance of deco. I don't know why Mikael wants to use a class 
rather than a function but if he wants to save state between calls this 
isn't going to help.

Something like this may work, and preserves the function name, type and 

from functools import wraps
class Decorator(object):
    def __init__(self, func):
        self._func = func

    def __new__(cls, func):
        decorator = object.__new__(cls)
        def wrapper(*args, **kwds):
            return decorator(*args, **kwds)
        return wrapper

class deco(Decorator):
    def __init__(self, func):
        self.calls = 0
        Decorator.__init__(self, func)
    def __call__(self, *args):
        self.calls += 1
        print "Decorator:", args, "called", self.calls, "times"
        return self._func(*args)

class C(object):
    def meth(self, arg):
        """meth's docstring"""
        print "meth %r %r" % (self, arg)
        return arg+1

inst1 = C()
inst2 = C()
print repr(inst1.meth), inst1.meth.__doc__

print inst1.meth(5)
print inst1.meth(inst2.meth(3))

<bound method C.meth of <__main__.C object at 0x00B45390>> meth's 
Decorator: (<__main__.C object at 0x00B45390>, 5) called 1 times
meth <__main__.C object at 0x00B45390> 5
Decorator: (<__main__.C object at 0x00B453D0>, 3) called 2 times
meth <__main__.C object at 0x00B453D0> 3
Decorator: (<__main__.C object at 0x00B45390>, 4) called 3 times
meth <__main__.C object at 0x00B45390> 4

Duncan Booth

More information about the Python-list mailing list