Python 如何绕过正常的属性查找来查找`__dict__`?

Tim*_*Tim 0 python attributes descriptor python-3.x python-internals

我知道__dict__ inobj.__dict__是 的描述符属性type(obj),因此查找obj.__dict__type(obj).__dict__['__dict__'].__get__(obj)

来自/sf/answers/3260320661/

很容易说它__dict__必须是一个描述符,因为__dict__将它实现为条目将需要您先找到 , __dict__然后才能找到__dict__,但是在查找其他属性时Python 已经绕过了正常的属性查找来查找__dict__,因此这并不像它最初听起来。如果描述符被替换为 each 中的一个'__dict__'__dict____dict__仍然可以找到。

“Python 已经绕过正常的属性查找来查找__dict__”如何?“正常属性查找”是什么意思?

根据链接中引用的上下文,我不认为作者在撰写该内容时提到了查找obj.__dict__type(obj).__dict__['__dict__'].__get__(obj).

Mar*_*ers 5

正常的属性查找是通过调用__getattribute__hook或者更准确地说是C-API tp_getattroslot 来完成的。对此的默认实现在PyObject_GenericGetAttrC-API 函数中

它的工作PyObject_GenericGetAttr,如果它们存在调用描述符,并看看实例__dict__。事实上,有一个__dict__描述符,但它是更快__getattribute__的,只是访问__dict__的实例内存插槽结构直接,这就是实际执行的功能:

if (dict == NULL) {
    /* Inline _PyObject_GetDictPtr */
    dictoffset = tp->tp_dictoffset;
    if (dictoffset != 0) {
        if (dictoffset < 0) {
            Py_ssize_t tsize;
            size_t size;

            tsize = ((PyVarObject *)obj)->ob_size;
            if (tsize < 0)
                tsize = -tsize;
            size = _PyObject_VAR_SIZE(tp, tsize);
            assert(size <= PY_SSIZE_T_MAX);

            dictoffset += (Py_ssize_t)size;
            assert(dictoffset > 0);
            assert(dictoffset % SIZEOF_VOID_P == 0);
        }
        dictptr = (PyObject **) ((char *)obj + dictoffset);
        dict = *dictptr;
    }
}
Run Code Online (Sandbox Code Playgroud)

注意内联_PyObject_GetDictPtr注释;这是性能优化,因为实例属性查找很频繁。

如果您尝试instance.__dict__从 Python 代码访问,则调用描述符;它是一个数据描述符对象,因此在查看实例属性之前被调用。