class 属性查找规则?
class attribute lookup rule?
>>> class D:
... __class__ = 1
... __name__ = 2
...
>>> D.__class__
<class 'type'>
>>> D().__class__
1
>>> D.__name__
'D'
>>> D().__name__
2
为什么D.__class__
return是class的名称,而D().__class__
return是[=]中定义的属性41=]D?
__class__
和 __name__
等内置属性从何而来?
我怀疑 __name__
或 __class__
是存在于 object
class 或其他地方的简单描述符,但这看不到。
据我理解,Python中的属性查找规则如下,省略描述符等条件..:
Instance --> Class --> Class.__bases__ and the bases of the other classes as well
鉴于 class 是 metaclass 的一个实例,type
在这种情况下,为什么 D.__class__
不查找 __class__
在 D.__dict__
?
名字__class__
和__name__
很特别。两者都是 数据描述符 。 __name__
是在 type
对象上定义的,__class__
是在 object
上定义的(所有新式 classes 的基础-class) :
>>> 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(用于 class 上的属性访问)将忽略 class __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, ...)
直接作为unbound方法使用,不是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 只是另一个实例。
因此,在查找 __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__
,它会在 D.__dict__
映射中找到 __name__
和 __class__
条目,然后再找到数据描述符在 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'
>>> class D:
... __class__ = 1
... __name__ = 2
...
>>> D.__class__
<class 'type'>
>>> D().__class__
1
>>> D.__name__
'D'
>>> D().__name__
2
为什么D.__class__
return是class的名称,而D().__class__
return是[=]中定义的属性41=]D?
__class__
和 __name__
等内置属性从何而来?
我怀疑 __name__
或 __class__
是存在于 object
class 或其他地方的简单描述符,但这看不到。
据我理解,Python中的属性查找规则如下,省略描述符等条件..:
Instance --> Class --> Class.__bases__ and the bases of the other classes as well
鉴于 class 是 metaclass 的一个实例,type
在这种情况下,为什么 D.__class__
不查找 __class__
在 D.__dict__
?
名字__class__
和__name__
很特别。两者都是 数据描述符 。 __name__
是在 type
对象上定义的,__class__
是在 object
上定义的(所有新式 classes 的基础-class) :
>>> 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(用于 class 上的属性访问)将忽略 class __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, ...)
直接作为unbound方法使用,不是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 只是另一个实例。
因此,在查找 __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__
,它会在 D.__dict__
映射中找到 __name__
和 __class__
条目,然后再找到数据描述符在 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'