属性覆盖对象__getattribute__的原因是什么?

huangapple go评论69阅读模式
英文:

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.

我注意到,与 classmethodstaticmethod 装饰器相反,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中,所有内置类型(例如objectintstrfloat)都遵循一种标准的定义方式。这些内置类型及其特殊方法都在底层C实现中使用槽位进行定义,例如float只需引用默认的PyObject_GenericGetAttr来处理tp_getattro,对于property也是一样。基本上,描述符指南中没有提及__getattribute__是正确的,因为它只是Python中内置类型定义的一个副产品(即如果它只是指向了名为PyObject_GenericGetAttr的适当命名指针,那就是用于“查找对象属性的正常方式”的通用实现)。

至于为什么classmethodvars输出中没有__getattribute__,那是因为classmethod的定义不包括tp_getattrotp_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版本起包含)中,提交消息中没有提到为什么它只是被更改为“使用默认值”。至于floatproperty类型,这个更改是在将近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).

huangapple
  • 本文由 发表于 2023年5月22日 10:00:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76302654.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定