Python如何绕过普通属性查找以找到__dict__? [英] How does Python bypass normal attribute lookup to find `__dict__`?
问题描述
我知道obj.__dict__
中的__dict__
是type(obj)
的描述符属性,因此对obj.__dict__
的查找是type(obj).__dict__['__dict__'].__get__(obj)
.
I understand that __dict__
in obj.__dict__
is a descriptor attribute of type(obj)
, so the lookup for obj.__dict__
is type(obj).__dict__['__dict__'].__get__(obj)
.
来自 https://stackoverflow.com/a/46576009
很容易说
__dict__
必须是一个描述符,因为 将其实现为__dict__
条目将需要您找到__dict__
,然后才能找到__dict__
,但是 Python已经存在 查找时绕过普通属性查找以找到__dict__
其他属性,因此不像最初那样引人注目 声音.如果描述符用'__dict__'
键替换 每个__dict__
,__dict__
仍然可以找到.
It's tempting to say that
__dict__
has to be a descriptor because implementing it as a__dict__
entry would require you to find the__dict__
before you can find the__dict__
, but Python already bypasses normal attribute lookup to find__dict__
when looking up other attributes, so that's not quite as compelling as it initially sounds. If the descriptors were replaced with a'__dict__'
key in every__dict__
,__dict__
would still be findable.
"Python已经如何绕过常规属性查找以找到__dict__
"? 常规属性查找"是什么意思?
How does "Python already bypasses normal attribute lookup to find __dict__
"? What does "normal attribute lookup" mean?
根据链接中引号的上下文,我认为作者写这篇文章时并没有提到obj.__dict__
的查找是type(obj).__dict__['__dict__'].__get__(obj)
.
According to the context of the quote in the link, I don't think when the author wrote that, he referred to that the lookup for obj.__dict__
is type(obj).__dict__['__dict__'].__get__(obj)
.
推荐答案
常规属性查找是通过调用 C-API tp_getattro
插槽.默认实现是在 PyObject_GenericGetAttr
C-API中功能.
Normal attribute lookup is done by calling the __getattribute__
hook, or more precisely, the C-API tp_getattro
slot. The default implementation for this is in the PyObject_GenericGetAttr
C-API function.
PyObject_GenericGetAttr
的工作是调用描述符(如果存在)并查看实例__dict__
.确实存在 一个__dict__
描述符,但是__getattribute__
直接访问实例内存结构中的__dict__
插槽更快,这就是
It is the job of PyObject_GenericGetAttr
to invoke descriptors if they exist, and to look at the instance __dict__
. And indeed, there is a __dict__
descriptor, but it is faster for __getattribute__
to just access the __dict__
slot in the instance memory structure directly, and that is what the actual implementation does:
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;
}
}
请注意 Inline _PyObject_GetDictPtr
注释;这是一种性能优化,因为实例属性查找非常频繁.
Note the Inline _PyObject_GetDictPtr
comment; this is a performance optimisation, as instance attribute lookups are frequent.
如果您尝试从Python代码访问instance.__dict__
,则将调用描述符;否则,将调用该描述符.它是一个数据描述符对象,因此在查看实例属性之前就将其调用.
If you try to access instance.__dict__
from Python code, then the descriptor is invoked; it is a data descriptor object so is invoked before instance attributes are even looked at.
这篇关于Python如何绕过普通属性查找以找到__dict__?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!