From Function to Method

Continuing our Python experiments:

Example 1.2. A function is more

>>> class C(object):
...     classattr = "attr on class"
...     def f(self):
...             return "function f"
>>> C.__dict__ 1
{'classattr': 'attr on class', '__module__': '__main__',
 '__doc__': None, 'f': <function f at 0x008F6B70>}
>>> cobj = C()
>>> cobj.classattr is C.__dict__['classattr'] 2
>>> cobj.f is C.__dict__['f'] 3
>>> cobj.f 4
<bound method C.f of <__main__.C instance at 0x008F9850>>
>>> C.__dict__['f'].__get__(cobj, C) 5
<bound method C.f of <__main__.C instance at 0x008F9850>>


Two innocent looking class attributes, a string 'classattr' and a function 'f'.


Accessing the string really gets it from the class's __dict__, as expected.


Not so for the function! Why?


Hmm, it does look like a different object. (A bound method is a callable object that calls a function (C.f in the example) passing an instance (cobj in the example) as the first argument in addition to passing through all arguments it was called with. This is what makes method calls on instance work.)


Here's the spoiler - this is what Python did to create the bound method. While looking for an attribute for an instance, if Python finds an object with a __get__() method inside the class's __dict__, instead of returning the object, it calls the __get__() method and returns the result. Note that the __get__() method is called with the instance and the class as the first and second arguments respectively.

It is only the presence of the __get__() method that transforms an ordinary function into a bound method. There is nothing really special about a function object. Anyone can put objects with a __get__() method inside the class __dict__ and get away with it. Such objects are called descriptors and have many uses.