Python 的面向对象功能是在基于函数的环境构建的。通过使用非数据描述器,这两方面完成了无缝融合。
Functions stored in class dictionaries get turned into methods when invoked.
Methods only differ from regular functions in that the object instance is
prepended to the other arguments. By convention, the instance is called
self but could be called this or any other variable name.
Methods can be created manually with types.MethodType which is
roughly equivalent to:
class MethodType:
"Emulate Py_MethodType in Objects/classobject.c"
def __init__(self, func, obj):
self.__func__ = func
self.__self__ = obj
def __call__(self, *args, **kwargs):
func = self.__func__
obj = self.__self__
return func(obj, *args, **kwargs)
To support automatic creation of methods, functions include the
__get__() method for binding methods during attribute access. This
means that functions are non-data descriptors that return bound methods
during dotted lookup from an instance. Here's how it works:
class Function:
...
def __get__(self, obj, objtype=None):
"Simulate func_descr_get() in Objects/funcobject.c"
if obj is None:
return self
return MethodType(self, obj)
Running the following class in the interpreter shows how the function
descriptor works in practice:
class D:
def f(self, x):
return x
The function has a qualified name attribute to support introspection:
>>>D.f.__qualname__
'D.f'
Accessing the function through the class dictionary does not invoke
__get__(). Instead, it just returns the underlying function object:
>>>D.__dict__['f']
Dotted access from a class calls __get__() which just returns the
underlying function unchanged:
>>>D.f
The interesting behavior occurs during dotted access from an instance. The
dotted lookup calls __get__() which returns a bound method object:
>>>d = D()
>>>d.f
>
Internally, the bound method stores the underlying function and the bound
instance:
>>>d.f.__func__
>>>d.f.__self__
<__main__.D object at 0x1012e1f98>
If you have ever wondered where self comes from in regular methods or where
cls comes from in class methods, this is it!