Python:__ getattribute__方法和描述符

时间:2014-07-21 11:18:33

标签: python attributes python-internals

根据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__本身就是一种方法!那怎么绑定一个对象(没有无限递归)?如果它在属性查找中是特殊的,那不会破坏删除旧式特殊套管的目的吗?

1 个答案:

答案 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代码的作用,当您在实例上使用属性访问时,这里有一整套函数:

当您访问类本身的属性而不是_PyObject_GenericGetAttrWithDict时,type->tp_getattro广告位由type_getattro() function提供服务,而{{3}}也会考虑元类。此版本也调用__get__,但将实例参数设置为None

此代码必须以递归方式调用__getattribute__来访问__dict__属性,因为它可以直接进入C结构。