Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #76179

Re: odd difference calling function from class or instance variable

From Peter Otten <__peter__@web.de>
Subject Re: odd difference calling function from class or instance variable
Date 2014-08-13 11:40 +0200
Organization None
References <201408131006549222-not@myrealaddresscom>
Newsgroups comp.lang.python
Message-ID <mailman.12913.1407922838.18130.python-list@python.org> (permalink)

Show all headers | View raw


GregS wrote:

> Hello,
> 
> This is my first post here so please gently inform me of any etiquette
> breaches.
> 
> I'm seeing a behaviour I can't explain with Python 3.4.1 when I call a
> function via a reference stored in an object.
> 
> When I assign the reference as a class variable, the reference has
> __self__ set, too, so I get an extra argument passed to the function.
> If I assign the reference as an instance variable, then __self__ is
> unset so no extra argument.
> 
> Here's what I mean:
> 
>>>> def print_args(*args):
> print(args)
> 
>>>> class C:
> ref = None
> 
>>>> C.ref = print_args    # assign to class variable
>>>> i = C()
>>>> i.ref()     # call via class variable - get a 'self' argument passed
> (<__main__.C object at 0x1071a05f8>,)
>>>> i.ref = print_args   # assign to instance variable
>>>> i.ref()     # call via instance variable: no arguments
> ()
> 
> If you look at i.ref.__self__ for the two cases, you'll see what's
> going on.  I've tried RTFMing but can't find the reason for the two
> behaviours.  Could someone provide an explanation for me, please?

When an attribute is found in the instance it is left as-is, so

i.ref()

is the same as

print_ref()

When the attribute is found in the class and itself has a __get__ attribute 

i.ref()

is equivalent to

print_ref.__get__(i, C)()

which creates a bound method object (i. e. it is assumed that the function  
implements a method):

>>> class C: pass
... 
>>> def f(self): pass
... 
>>> f.__get__(C(), C)
<bound method C.f of <__main__.C object at 0x7f3a99ce86a0>>

As you have seen a bound method implicitly passes the instance as the first 
arg to the function. The underlying mechanism is called "descriptor 
protocol" and is also used to implement properties.

If you need to store a function in the class you can wrap it as a 
staticmethod:

>>> def print_args(*args): print(args)
... 
>>> class C:
...     ref = staticmethod(print_args)
... 
>>> C().ref()
()

Back to comp.lang.python | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

odd difference calling function from class or instance variable GregS <not@my.real.address.com> - 2014-08-13 10:06 +0100
  Re: odd difference calling function from class or instance variable Peter Otten <__peter__@web.de> - 2014-08-13 11:40 +0200
  Re: odd difference calling function from class or instance variable Chris Angelico <rosuav@gmail.com> - 2014-08-13 19:45 +1000
  Re: odd difference calling function from class or instance variable GregS <not@my.real.address.com> - 2014-08-13 11:20 +0100
    Re: odd difference calling function from class or instance variable Chris Angelico <rosuav@gmail.com> - 2014-08-13 20:29 +1000

csiph-web