Why Methods Bind Automatically

class Foo:
    def bar(self):
        return "bar"

f = Foo()
print(f.bar)

This prints something like <bound method Foo.bar of <...>> rather than the plain function object stored in Foo.__dict__['bar']. What makes that happen?

A

f.bar triggers getattr, which Python auto-generates for every class to wrap functions into bound methods

B

Functions implement the descriptor protocol: they define get, so accessing bar through an instance invokes function.get(f, Foo), which returns a bound method wrapping f

C

Python hardcodes a special case for names that look like method calls, separate from normal attribute lookup

D

Foo.init copies every function from the class body into the instance's own dict, binding self at construction time