Имена __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, ...)
используется непосредственно в качестве несвязанного метода, не D.__getattribute__()
, потому что all special method access goes to the type).
См Descriptor Howto собой, что представляет дескриптор данных и почему это имеет значение:
Если объект определяет как __get__()
и __set__()
, он считается дескриптором данных. Дескрипторы, которые определяют только __get__()
, называются дескрипторами без данных (они обычно используются для методов, но возможны другие виды использования).
Дескрипторы данных и данных, отличные от того, как вычисляются переопределения в отношении записей в словаре экземпляра. Если словарь экземпляра имеет запись с тем же именем, что и дескриптор данных, дескриптор данных имеет приоритет. Если словарь экземпляра имеет запись с тем же именем, что и дескриптор не данных, запись словаря имеет приоритет.
Для дескрипторов данных на 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
(так, на 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'
я получаю большинство частей вашего ответа и проверить, что: правила для атрибута поиска различается для классов и экземпляров. Я вижу «тип .__ getattribute__» дает более высокий приоритет дескрипторам данных, такой же, как 'object .__ getattribute__'. Но оба типа .__ getattribute__' и 'object .__ getattribute__' проверяют тип объекта. Если это экземпляр класса, поиск '__dict__' выполняется перед дескрипторами данных. Это правильно? – direprobs
@ direprobs: происходит то, что вы начинаете поиск атрибута на объекте, а Python всегда выполняет 'type (object) .__ getattribute __ (object, attribute_name)'; для объектов класса, которые являются 'type .__ getattribute__', для экземпляров, которые являются' object .__ getattribute__' (в обоих случаях, если они не переопределены подтипом/подклассом). Таким образом, «проверка типа» имеет место * до того, как * '__getattribute__' даже называется. –
Да, это так. Дело в том, что я попробовал 'type .__ getattribute __ (A, '__class __')', который возвращает ''. Таким образом, оба типа: .__ getattribute__ и 'object .__ getattribute__' рассматривают дескрипторы данных с более высоким приоритетом, чем' __dict__' для (классы), а не (экземпляры). Но когда я запускал 'type .__ getattribute __ (A(), '__class __')', это возвращает '1'. Это говорит о том, что существует некоторый тип проверки типов (будь то объект, переданный в '__getattribute__', является классом или экземпляром класса), если это класс, тогда Python будет сначала искать дескрипторы данных. –
direprobs