1

I have experimented a little. By checking __dict__ of a class or an instance, I can see some method has type function and some bound method. The experiment is messy, and I can't figure the following questions out.

In Python 3, what are the differences between methods of a class or instance, which are "function" and which are "bound method"?

How are they created respectively?

Can they both be called on a class and on an instance? Will they both be implicitly given an instance as their first argument?

Is "bound method" an attribute of a class or an instance of a class?

Thanks.

Tim
  • 1
  • 122
  • 314
  • 481
  • 1
    Possible duplicate of [What is the difference between a function, an unbound method and a bound method?](https://stackoverflow.com/questions/11949808/what-is-the-difference-between-a-function-an-unbound-method-and-a-bound-method) – Maciej Jureczko Sep 05 '17 at 14:40

1 Answers1

5

This answer will be really technical, I hope it's still understandable though. The problem is that it requires knowledge of the descriptor protocol to understand how methods in Python work.

All functions in Python 3 are descriptors, to be precise they are non-data descriptors. That means they implements a __get__ method - but no __set__ method.

That's interesting because descriptors can do (almost) anything if they are looked up on a class or an instance.

By the definition of the __get__ method in Pythons data model:

object.__get__(self, instance, owner)

Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner. This method should return the (computed) attribute value or raise an AttributeError exception.

So what does this have to do with the difference between function and bound_method?

It's easy, a function accessed through __get__ with an instance=None will return itself:

>>> def func(x): return x
>>> func.__get__(None, object)
<function __main__.func>
>>> func.__get__(None, object) is func
True

While it will be a bound_method if accessed with an not-None instance:

>>> func.__get__(object())
<bound method func of <object object at 0x00000155614A0610>>

It's basically just a wrapper around func with the instance stored:

>>> m = func.__get__(object())
>>> m.__self__   # stored instance
<object at 0x155614a0650>

>>> m.__func__  # stored function
<function __main__.func>

However, when called, it will pass the instance as first argument to the wrapped function:

>>> m()
<object at 0x155614a0650>

So, bound methods will pass the instance as first argument, while functions do not (they requires all attributes).


So when you look at a class all normal methods will display as functions while all normal methods on an instance will be bound methods.

Why did I mention normal methods? Because you can define arbitrary descriptors. For example the Python built-ins already contain several exceptions:

  • classmethod
  • staticmethod
  • property (this is in fact a data-descriptor so I'll neglect it in the following discussion)

classmethods will display as bound method even when looked up on the class. That's because they are meant to be callable on the class and pass the class to the function, no matter if they are called on the class or the instance:

class Test(object):
    @classmethod
    def func(x):
        return x
    
>>> Test.func
<bound method Test.func of <class '__main__.Test'>>
>>> Test().func
<bound method Test.func of <class '__main__.Test'>>

And staticmethods always display as functions because they never pass anything additional to the function:

class Test(object):
    @staticmethod
    def func(x):
        return x
    
>>> Test().func
<function __main__.Test.func>
>>> Test.func
<function __main__.Test.func>

So it's easily possible to see also bound methods on the class (e.g. classmethods) and likewise one could also find normal functions on instances (e.g. staticmethods).

Community
  • 1
  • 1
MSeifert
  • 118,681
  • 27
  • 271
  • 293
  • Thanks. "So it's easily possible to have bound methods on the class and normal functions on instances" for what kind of methods? Ordinary methods have bound methods on instances and normal functions on the class, static methods have functions on both the class and instances, and class methods have bound methods on both the class and instances. None of the three "have bound methods on the class and normal functions on instances". – Tim Sep 06 '17 at 05:51
  • @Tim I didn't mean the same "method" when I wrote that sentence, however it would be easily possible with an own descriptor. I edited the answer to make it a bit less ambiguous :) – MSeifert Sep 06 '17 at 09:50