__getattribute__ 如何取值?

How does __getattribute__ fetch a value?

class test():
  name = 'arthur'

  def __getattribute__(self, value):
    return super().__getattribute__(value)

x = test()
x.name

------------------------------------------
Output: 'arthur'

我正在尝试了解 __getattribute__ 的基本机制。我理解(希望如此)在这种情况下 super().__getattribute__(value) 会接触到对象 class。但是 object 实际上是如何从 test() class 中获取 name 值的呢?如果在避免递归的情况下自己在 class 中编码,如何使用 __getattribute__ 获取属性值?

正如我所说,我想了解底层机制,我知道这不是您通常处理事情的方式。

谢谢!

您不能在 Python 中编写此代码。这是 Python 调用的 C 函数:

PyObject *
PyObject_GetAttr(PyObject *v, PyObject *name)
{
    PyTypeObject *tp = Py_TYPE(v);

    if (!PyUnicode_Check(name)) {
        PyErr_Format(PyExc_TypeError,
                     "attribute name must be string, not '%.200s'",
                     name->ob_type->tp_name);
        return NULL;
    }
    if (tp->tp_getattro != NULL)
        return (*tp->tp_getattro)(v, name);
    if (tp->tp_getattr != NULL) {
        const char *name_str = PyUnicode_AsUTF8(name);
        if (name_str == NULL)
            return NULL;
        return (*tp->tp_getattr)(v, (char *)name_str);
    }
    PyErr_Format(PyExc_AttributeError,
                 "'%.50s' object has no attribute '%U'",
                 tp->tp_name, name);
    return NULL;
}

https://github.com/python/cpython/blob/8289e27393395ee903bd096d42e07c112d7f15c6/Objects/object.c#L1001-L1024

这是object.__getattribute__。在您的示例中调用它是因为所有 类 都继承自 object.

首先,__getattribute__ 是一个神奇的方法(又名 dunder method/double 下划线方法)。这是一个 property/attribute 访问器方法,它会在每次 property/attribute 访问时进行拦截,即使 property/attribute 在 class 本身中可用也是如此。另一方面,仅当您访问的 属性 不存在于 class/instance 中时,才会调用 __getattr__ 魔法方法。无论如何...

还有一件更重要的事情需要注意,正如您可能已经知道的那样,所有 class 都是 extends/inherits 基数 object class 隐式或显式.所以,任何你定义的 class,默认父 class 是内置的 object class。你一问就糊涂了:

I understand (hopefully) that super().__getattribute__(value) reaches out to the object class in this case. But how actually does object fetch the name value out of the test() class?

所以让我们先看一些基本的例子:

class Foo:
    def __init__(self, name):
        self.name = name

    def __getattribute__(self, name):
        return super().__getattribute__(name)

等同于

class Foo(object):
    def __init__(self, name):
        self.name = name

    def __getattribute__(self, name):
        return object.__getattribute__(self, name)

所以,当你打电话给

object.__getattribute__(self, name)

您正在将上下文(class 的实例)显式传递给父级 (object) class。所以 parent/object class 知道上下文并从传递的实例中获取属性。另一方面,当你打电话时:

super().__getattribute__(name)

Python 为您设置上下文。所以,你可以想象这样的事情:

super(test, self).__getattribute__(name) # it's valid

但在这种情况下,它是隐式的,这就是 super() 调用知道在哪里查找属性的方式。值得一提的是,Python的super()内置函数returns一个代理object,一个替代对象,可以通过委托调用基class的方法而且 super() 可以带两个参数(正如您在前面的代码片段中看到的),第一个是 subclass 类型(在本例中是 test),第二个参数是一个对象,该子对象的一个​​实例class (test).

Python 3中,super(test, self)调用等同于无参数super()调用。希望我已经澄清了你的困惑。您可以阅读更多关于 super().