Decorating methods - where do my arguments go?
Peter Otten
__peter__ at web.de
Fri May 8 12:39:29 EDT 2009
Mikael Olofsson wrote:
> Hi all!
>
> I have long tried to avoid decorators, but now I find myself in a
> situation where I think they can help. I seem to be able to decorate
> functions, but I fail miserably when trying to decorate methods. The
> information I have been able to find on-line focuses on decorating
> functions, and do not mention any special problem regarding methods.
>
> Consider the following example. I start by defining a simple decorator:
>
> >>> class test_decorator(object):
> ... def __init__(self,func):
> ... self._func = func
> ... def __call__(self, *args):
> ... print 'Decorator:', args
> ... self._func(*args)
>
> Then I decorate a function:
>
> >>> @test_decorator
> ... def func(*args):
> ... print 'Function: ', args
>
> Let's try that:
>
> >>> func(1,2,3)
> Decorator: (1, 2, 3)
> Function: (1, 2, 3)
>
> OK! That was what I expected. Let's decorate a method:
>
> >>> class cls(object):
> ... @test_decorator
> ... def meth(self,*args):
> ... print 'Method: ', args
>
> Then try that:
>
> >>> cls().meth(1,2,3)
> Decorator: (1, 2, 3)
> Method: (2, 3)
>
> Oops! That's weird. I had expected - or at least wanted - the same
> result as for the function above.
>
> Where did the first argument go? If it was sent to the original method
> meth as the real first argument (self), then why did I not get an
> exception?
>
> More importantly: How do I write a decorator that does not drop arguments?
>
> I guess it all has to do with the fact that the returned callable isn't
> a method of cls. Is it possible to write a decorator that returns a
> callable that is a method of cls, when used on methods in cls?
>
> /MiO
You have to turn your decorator into a descriptor by providing a __get__()
method. A primitive example:
class test_decorator(object):
def __init__(self,func):
self._func = func
def __call__(self, *args):
print 'Decorator:', args
self._func(self.inst, *args)
def __get__(self, inst, cls):
self.inst = inst
return self
Read more about the details at
http://users.rcn.com/python/download/Descriptor.htm
Peter
More information about the Python-list
mailing list