Understanding decorator and class methods
Rotwang
sg552 at hotmail.co.uk
Wed Jan 8 18:17:22 EST 2014
On 08/01/2014 19:56, axis.of.weasel at gmail.com wrote:
> can someone please explain why the following works, in contrast to the second example?
>
> def decorator(func):
> def on_call(*args):
> print args
> return func(args)
> return on_call
>
> class Foo:
> @decorator
> def bar(self, param1):
> print 'inside bar'
>
> f=Foo()
> f.bar(4) # from where is the decorator getting the Foo instance?
>
>
>
> I understand why the following works/does not work
>
> class decorator2:
> def __init__(self, func):
> self.func=func
> def __call__(self, *args):
> self.func(*args)
>
> class Foo2:
> @decorator2
> def bar2(self, param): pass
>
>
> f2 = Foo2()
> Foo2.bar2(f2, 4) # works, Foo2 instance and param are passed to decorator2 call
> f2.bar2(4) # does not work, Foo2 instance is missing, decorator2 cannot invoke method bar
From http://docs.python.org/3/reference/datamodel.html:
Instance methods
An instance method object combines a class, a class instance and
any callable object (normally a user-defined function).
[...]
User-defined method objects may be created when getting an
attribute of a class (perhaps via an instance of that class), if
that attribute is a user-defined function object or a class method
object.
[...]
Note that the transformation from function object to instance
method object happens each time the attribute is retrieved from the
instance. In some cases, a fruitful optimization is to assign the
attribute to a local variable and call that local variable. Also
notice that this transformation only happens for user-defined
functions; other callable objects (and all non-callable objects)
are retrieved without transformation.
Notice the last sentence in particular. After being decorated by
decorator2 Foo2.bar2 is not a user-defined function (i.e. an instance of
types.FunctionType), so is not transformed into a method upon being
accessed through an instance. I suppose you could create a class that
mimics the behaviour of methods, though I don't know why you would want
to. The following is tested with 3.3.0; I expect someone who knows more
than I will probably be along soon to point out why it's stupid.
class decorator3:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('Calling func(self, *%r, **%r)' % (args, kwargs))
return self.func(self.__self__, *args, **kwargs)
def __get__(self, instance, owner):
self.__self__ = instance
return self
class Foo3:
@decorator3
def bar3(self, param):
return self, param
>>> f3 = Foo3()
>>> f3.bar3('param')
Calling func(self, *('param',), **{})
(<__main__.Foo3 object at 0x0000000002BDF198>, 'param')
More information about the Python-list
mailing list