gpt4 book ai didi

python - 类属性查找规则?

转载 作者:太空狗 更新时间:2023-10-29 22:21:26 25 4
gpt4 key购买 nike

>>> class D:
... __class__ = 1
... __name__ = 2
...
>>> D.__class__
<class 'type'>
>>> D().__class__
1
>>> D.__name__
'D'
>>> D().__name__
2

为什么D.__class__返回类名,而D().__class__返回类D中定义的属性?

__class____name__ 等内置属性从何而来?

我怀疑 __name____class__ 是存在于 object 类或某处的简单描述符,但这看不到。

在我的理解中,Python中的属性查找规则如下,省略了描述符等条件..:

Instance --> Class --> Class.__bases__ 以及其他类的基础

鉴于类是元类的实例,在这种情况下,type 为什么 D.__class__ 不查找 __class__ D.__dict__ 中的?

最佳答案

名字__class____name__很特别。两者都是数据描述符__name__type 上定义对象,__class__object 上定义(所有新型类的基类):

>>> type.__dict__['__name__']
<attribute '__name__' of 'type' objects>
>>> type.__dict__['__name__'].__get__
<method-wrapper '__get__' of getset_descriptor object at 0x1059ea870>
>>> type.__dict__['__name__'].__set__
<method-wrapper '__set__' of getset_descriptor object at 0x1059ea870>
>>> object.__dict__['__class__']
<attribute '__class__' of 'object' objects>
>>> object.__dict__['__class__'].__get__
<method-wrapper '__get__' of getset_descriptor object at 0x1059ea2d0>
>>> object.__dict__['__class__'].__set__
<method-wrapper '__set__' of getset_descriptor object at 0x1059ea2d0>

因为它们是数据描述符,所以 type.__getattribute__ method (用于类的属性访问)将忽略类中设置的任何属性 __dict__并且只使用描述符本身:

>>> type.__getattribute__(Foo, '__class__')
<class 'type'>
>>> type.__getattribute__(Foo, '__name__')
'Foo'

有趣的事实:type源自 object (Python 中的一切 都是对象)这就是为什么 __class__type 上找到检查数据描述符时:

>>> type.__mro__
(<class 'type'>, <class 'object'>)

( type.__getattribute__(D, ...) 直接用作未绑定(bind)方法,而不是 D.__getattribute__() ,因为 all special method access goes to the type )。

参见 Descriptor Howto什么是数据描述符及其重要性:

If an object defines both __get__() and __set__(), it is considered a data descriptor. Descriptors that only define __get__() are called non-data descriptors (they are typically used for methods but other uses are possible).

Data and non-data descriptors differ in how overrides are calculated with respect to entries in an instance’s dictionary. If an instance’s dictionary has an entry with the same name as a data descriptor, the data descriptor takes precedence. If an instance’s dictionary has an entry with the same name as a non-data descriptor, the dictionary entry takes precedence.

对于 type 上的数据描述符,一个类只是另一个实例。

所以在查找 __class__ 时或 __name__属性,在 D.__dict__ 中定义什么并不重要命名空间,因为在 type 形成的命名空间中可以找到数据描述符这是 MRO。

这些描述符在 typeobject.c C code 中定义:

static PyGetSetDef type_getsets[] = {
{"__name__", (getter)type_name, (setter)type_set_name, NULL},
/* ... several more ... */
}

/* ... */

PyTypeObject PyType_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"type", /* tp_name */
/* ... many type definition entries ... */
type_getsets, /* tp_getset */
/* ... many type definition entries ... */
}

/* ... */

static PyGetSetDef object_getsets[] = {
{"__class__", object_get_class, object_set_class,
PyDoc_STR("the object's class")},
{0}
};

PyTypeObject PyBaseObject_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"object", /* tp_name */
/* ... many type definition entries ... */
object_getsets, /* tp_getset */
/* ... many type definition entries ... */
}

在实例上,object.__getattribute__被使用,它会找到 __name____class__ D.__dict__ 中的条目在它找到 object 上的数据描述符之前进行映射或 type .

但是,如果您省略其中任何一个,则在 D() 上查找名称只会__class__作为 D 的 MRO 中的数据描述符(所以,在 object 上)。 __name__未找到,因为解析实例属性时未考虑元类型。

因此你可以设置__name__在一个实例上,但不是 __class__ :

>>> class E: pass
...
>>> e = E()
>>> e.__class__
<class '__main__.E'>
>>> e.__name__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'E' object has no attribute '__name__'
>>> e.__dict__['__class__'] = 'ignored'
>>> e.__class__
<class '__main__.E'>
>>> e.__name__ = 'this just works'
>>> e.__name__
'this just works'

关于python - 类属性查找规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39169600/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com