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)
Because a.bar
is an instance attribute, the descriptor protocol is not invoked, so a.bar
is the exact same object as bar
.
(This is an extremely condensed version of the contents of the Descriptor HowTo Guide, in particular the section on methods. I highly recommended reading it.)
The lookup for a.bar
proceeds by first looking for bar
in A.__dict__
. When it isn't found, Python looks in a.__dict__
, and finds a function
to call: end of story.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…