英文:
Why does property override object.__getattribute__?
问题
I noticed that contrary to the classmethod
and staticmethod
decorators, the property
decorator overrides the object.__getattribute__
method. The functionality of the property
decorator doesn’t seem to require this override (cf. the equivalent Python code in the Descriptor HowTo Guide). So which behavior exactly does this override implement? Please provide a link to the corresponding C code in the CPython repository, and optionally an equivalent Python code.
我注意到,与 classmethod
和 staticmethod
装饰器相反,property
装饰器覆盖了 object.__getattribute__
方法。 property
装饰器的功能似乎不需要此覆盖(参考Descriptor HowTo Guide中的等效Python代码)。那么这个覆盖实际上实现了哪些行为?请提供到 CPython存储库 中相应C代码的链接,以及可选的等效Python代码。
英文:
I noticed that contrary to the classmethod
and staticmethod
decorators, the property
decorator overrides the object.__getattribute__
method:
>>> list(vars(classmethod))
['__new__', '__repr__', '__get__', '__init__', '__func__', '__wrapped__', '__isabstractmethod__', '__dict__', '__doc__']
>>> list(vars(staticmethod))
['__new__', '__repr__', '__call__', '__get__', '__init__', '__func__', '__wrapped__', '__isabstractmethod__', '__dict__', '__doc__']
>>> list(vars(property))
['__new__', '__getattribute__', '__get__', '__set__', '__delete__', '__init__', 'getter', 'setter', 'deleter', '__set_name__', 'fget', 'fset', 'fdel', '__doc__', '__isabstractmethod__']
The functionality of the property
decorator doesn’t seem to require this override (cf. the equivalent Python code in the Descriptor HowTo Guide). So which behaviour exactly does this override implement? Please provide a link to the corresponding C code in the CPython repository, and optionally an equivalent Python code.
答案1
得分: 3
以下是您要翻译的内容:
在CPython中,所有内置类型(例如object
、int
、str
、float
)都遵循一种标准的定义方式。这些内置类型及其特殊方法都在底层C实现中使用槽位进行定义,例如float
只需引用默认的PyObject_GenericGetAttr
来处理tp_getattro
,对于property
也是一样。基本上,描述符指南中没有提及__getattribute__
是正确的,因为它只是Python中内置类型定义的一个副产品(即如果它只是指向了名为PyObject_GenericGetAttr
的适当命名指针,那就是用于“查找对象属性的正常方式”的通用实现)。
至于为什么classmethod
的vars
输出中没有__getattribute__
,那是因为classmethod
的定义不包括tp_getattro
或tp_getattr
,但这意味着它的__getattribute__
会回退到其父类的object.__getattribute__
(在Python中检查classmethod.__getattribute__ is object.__getattribute__
的输出)。至于为什么classmethod
没有明确的链接,而其他各种内置类型定义了与PyObject_GenericGetAttr
的明确链接(尽管在几乎所有代码使用中,无论做出哪种决定,结果都几乎相同),您可能需要向开发者询问。
补充说明:虽然在大约12年前(2012年),即Python 3.2正在开发的时候,classmethod
确实设置了tp_getattro
,但在那之后的提交2cf936fe7a55
(自2.7.5和3.3.0a1版本起包含)中,提交消息中没有提到为什么它只是被更改为“使用默认值”。至于float
和property
类型,这个更改是在将近22年前(2001年)的合并提交6d6c1a35e08b
中引入的,该提交带来了PEP-252中概述的更改,即描述符协议本身。请注意,它将所有标准类型的tp_getattro
设置为PyObject_GenericGetAttr
,这些标准类型之前没有定义它(以及classmethod
,这是这种类型首次亮相的地方)。
英文:
To refresh yourself on what __getattribute__
is and how this is implemented in CPython, please refer to this very excellent answer first, as that answers contains all the detailed background information on what to look for in the CPython source, and the paragraphs below will reference those details without further explanations.
In CPython, all builtin types (e.g. object
, int
, str
, float
) all follow a standard way on how they are defined. These builtin types with their dunder methods are all slotted in the underlying C implementation, for example float
simply reference the default PyObject_GenericGetAttr
for tp_getattro
, and this is exactly the same for property
. Essentially, the descriptor howto guide is correct in omitting any references to __getattribute__
, as its presence is nothing more than an artifact on how builtin types in Python are defined (i.e. they all point to the same generic implementation for "the normal way of looking for object attributes" if it's just a pointer to the aptly named PyObject_GenericGetAttr
).
As for why classmethod
does not have __getattribute__
appear as part of its vars
output, that's because the definition for classmethod
does not include tp_getattro
nor tp_getattr
, but it just means that its __getattribute__
falls back to its parent's, which is object.__getattribute__
(check in Python for output of classmethod.__getattribute__ is object.__getattribute__
). As for why classmethod
is defined without the explicit linkage while various other builtin types define an explicit linkage to PyObject_GenericGetAttr
(despite the outcome of either decisions being functionally the same in nearly all code usage), you may have to ask the developers themselves.
Addendum: though at some point 12 years ago (2012), around the time of Python 3.2 was being developed, classmethod
did have tp_getattro
set, but subsequent to that commit 2cf936fe7a55
(included since 2.7.5 and 3.3.0a1) - the commit message has no hints as to why it was simply changed to "use defaults". As for float
and property
type, the change was introduced way back in the merge commit 6d6c1a35e08b
from nearly 22 years ago (2001) that brought in the changes outlined in PEP-252 which is the descriptor protocol itself. Note that it set all tp_getattro
to PyObject_GenericGetAttr
for standard types that didn't have it defined before (and likewise for classmethod
which is where this type made its debut).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论