根据python描述符的本指南 https://docs.python.org/2/howto/descriptor.html
新样式类中的方法对象是使用描述符实现的,以避免在属性查找中特殊包装它们。
我理解这一点的方法是,有一个方法对象类型实现__get__并在使用实例调用时返回绑定方法对象,而在没有实例且只调用类时调用未绑定方法对象。文章还指出,这个逻辑是在object .__ getattribute__方法中实现的。像这样:
def __getattribute__(self, key):
"Emulate type_getattro() in Objects/typeobject.c"
v = object.__getattribute__(self, key)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
但是对象.__ getattribute__本身就是一种方法!那怎么绑定一个对象(没有无限递归)?如果它在属性查找中是特殊的,那不会破坏删除旧式特殊套管的目的吗?
答案 0 :(得分:6)
实际上,在CPython中,默认的__getattribute__
实现不是 Python 方法,而是用C实现。它可以访问对象槽(C结构中表示Python对象的条目)直接,无需费心去完成讨厌的属性访问例程。
仅仅因为你的 Python 代码必须这样做,并不意味着C代码必须这样做。 : - )
如果您确实实施了Python __getattribute__
方法,只需使用object.__getattribute__(self, attrname)
,或者更好,super(YourClassName, self).__getattribute__(attrname)
来访问self
上的属性。这样你就不会遇到递归。
在CPython实现中,属性访问实际上由C类型对象中的tp_getattro
slot处理,并回退到tp_getattr
slot。这样你就可以避免递归。
为了详尽无遗并完全暴露C代码的作用,当您在实例上使用属性访问时,这里有一整套函数:
Python将属性访问权限转换为对PyObject_GetAttr()
C function的调用。 implementation for that function会查找您班级的tp_getattro
或tp_getattr
位。
object
类型tp_getattr
filled _PyObject_GenericGetAttrWithDict
function。此功能是您的object.__getattribute__
方法(名称和广告位之间的special table地图)。
此函数可以通过tp_dict
slot访问实例__dict__
对象,但对于描述符(包括方法),则使用_PyType_Lookup
function。
_PyType_Lookup
在类(和超类)上查找属性。代码使用指向cl_dict
(自定义Python类)和tp_dict
的直接指针来引用类和类型字典。
如果_PyType_Lookup
找到描述符,则返回_PyObject_GenericGetAttrWithDict
并调用该对象上的tp_descr_get
函数(__get__
挂钩)。< / p>
当您访问类本身的属性而不是_PyObject_GenericGetAttrWithDict
时,type->tp_getattro
广告位由type_getattro()
function提供服务,而{{3}}也会考虑元类。此版本也调用__get__
,但将实例参数设置为None
。
此代码必须以递归方式调用__getattribute__
来访问__dict__
属性,因为它可以直接进入C结构。