On 08/01/2014 19:56, axis.of.wea...@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')
--
https://mail.python.org/mailman/listinfo/python-list