In the code below, the object
a has two functions as attributes: one is a class attribute while one is its own instance attribute.
class A: def foo(*args): pass a = A() def bar(*args): pass a.bar = bar print(a.foo) print(a.bar)
What I expected was that both
foo() would be methods of the object
a, but, from the output of this code, it turns out that this is not the case—only
foo is a method of
<bound method A.foo of <__main__.A object at 0x0000016F5F579AF0>> <function bar at 0x0000016F5F5845E0>
So what exactly is a method in Python? Is it a class attribute that holds a function definition, which seems to be the case.
And why isn’t the attribute
bar considered a method by Python? What exactly is the idea behind this behaviour of Python?
A method is an instance of the class
method returned by, among other things, the
__get__ method of a
function-valued class attribute.
a.bar is an instance attribute, not a class attribute.
When looking for
a.foo, Python first looks for
A.foo. Having found it, it next checks if its value has a
__get__ method (which, as a
function value, it does.) Because
A.foo is a descriptor (i.e, has a
__get__ method), its
__get__ method is called:
a.foo is the same as
A.foo.__get__(a, A). The return value is a
method object, whose
__call__ method calls the underlying function with the object and its own arguments. That is,
a.foo(x) == A.foo.__get__(a, A)(x) == A.foo(a, x)
a.bar is an instance attribute, the descriptor protocol is not invoked, so
a.bar is the exact same object as
The lookup for
a.bar proceeds by first looking for
A.__dict__. When it isn’t found, Python looks in
a.__dict__, and finds a
function to call: end of story.