Decorating methods - where do my arguments go?

Mikael Olofsson mikael at isy.liu.se
Mon May 11 10:06:11 EDT 2009


Peter Otten wrote:
> 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

Thanks! Works perfectly for methods, as far as I can see. That's 
perfectly OK, since that is what I was asking for. What I failed to 
include in my original post is that I intend to use the decorator for 
functions as well. The above fails for functions on the second row of 
__call__ with

     AttributeError: 'test_decorator' object has no attribute 'inst'

It seems to me like __get__ is not called when decorating a function. I 
guess there's no reasonable value for inst in that case. It might be the 
function itself, but it doesn't make sense to call the function with 
itself as its first argument, when it isn't supposed to be called that way.

George Sakkis decorator function solution seems to work equally well for 
functions and methods. However, I prefer the cleaner encapsulation given 
by a class. Based on those observations, I think I will use the 
following approach:

 >>> class test_decorator(object):
...     _inst = None
...     def __init__(self,func):
...         self._func = func
...     def __call__(self, *args):
...         print 'Decorator:', args
...         if self._inst is None:
...             print 'We seem to be decorating a function.'
...             self._func(*args)
...         else:
...             print 'We seem to be decorating a method.'
...             self._func(self._inst,*args)
...     def __get__(self, inst, cls):
...         self._inst = inst
...         return self
...
 >>>
 >>> @test_decorator
... def func(*args):
...     print 'Function: ', args
...
 >>>
 >>> func(1,2,3)
Decorator: (1, 2, 3)
We seem to be decorating a function.
Function:  (1, 2, 3)
 >>>
 >>> class cls(object):
...     @test_decorator3
...     def meth(self,*args):
...         print 'Method:   ', args
...
 >>>
 >>> cls().meth(1,2,3)
Decorator: (1, 2, 3)
We seem to be decorating a method.
Method:    (1, 2, 3)

If there are any drawbacks with this approach that I fail to see, please 
enlighten me.

/MiO



More information about the Python-list mailing list