Nazwy __class__
i __name__
są specjalne. Oba są deskryptorami danych . __name__
jest zdefiniowana w obiekcie type
, __class__
jest zdefiniowana na object
(baza-klasa wszystkich klas w nowym stylu):
>>> 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>
Ponieważ są deskryptory danych, type.__getattribute__
method (używany do dostępu atrybut klasy) zignoruje wszelkie atrybuty określone w klasie __dict__
i używać tylko deskryptory się:
>>> type.__getattribute__(Foo, '__class__')
<class 'type'>
>>> type.__getattribute__(Foo, '__name__')
'Foo'
Ciekawostka: type
wywodzi object
(wszystko Pythona Przedmiotem), dlatego __class__
znajduje się na type
przy sprawdzaniu danych deskryptorów:
>>> type.__mro__
(<class 'type'>, <class 'object'>)
(type.__getattribute__(D, ...)
stosuje się bezpośrednio w postaci niezwiązanej metodzie nie D.__getattribute__()
, ponieważ all special method access goes to the type).
Zobacz Descriptor Howto o co stanowi deskryptor danych i dlaczego to się liczy:
Jeśli obiekt definiuje zarówno __get__()
i __set__()
, uważa się deskryptor danych. Deskryptory, które definiują tylko __get__()
nazywane są deskryptorami niebędącymi danymi (są zwykle używane do metod, ale możliwe są inne zastosowania).
Deskryptory danych i inne niż dane różnią się sposobem obliczania przesłonięć w odniesieniu do wpisów w słowniku instancji. Jeśli słownik instancji ma pozycję o takiej samej nazwie jak deskryptor danych, pierwszeństwo ma deskryptor danych. Jeśli słownik instancji ma pozycję o takiej samej nazwie jak deskryptor niebędący deskryptorem, pierwszeństwo ma pozycja w słowniku.
Dla deskryptorów danych na type
, klasa jest po prostu kolejną instancją.
Więc kiedy patrzy się na __class__
lub __name__
atrybuty, to nie ma znaczenia, co jest zdefiniowane w przestrzeni nazw D.__dict__
, bo albo deskryptor dane znajdują się w przestrzeni nazw utworzonym przez type
i to MRO.
te deskryptory są definiowane w 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 ... */
}
W przypadkach object.__getattribute__
służy, i będzie ona znaleźć __name__
i __class__
wpisy w mapowaniu D.__dict__
zanim będzie ona znaleźć deskryptorów danych na object
lub type
.
Jeśli pominąć albo jednak potem patrząc na nazwiska D()
tylko __class__
jako deskryptor danych w MRO z D
(tak, to na object
). __name__
nie znaleziono, ponieważ metatypy nie są uwzględniane podczas rozwiązywania atrybutów instancji.
Jako takie można ustawić __name__
na przykład, ale nie __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'
uzyskać większość części odpowiedź i przetestować, że: przepisy dla odnośnika atrybutu różni się dla klas i instancji. Widzę, że 'type .__ getattribute__' nadaje deskryptorom danych wyższy priorytet, taki sam jak' object .__ getattribute__'. Ale zarówno 'type .__ getattribute__', jak i' object .__ getattribute__' sprawdzają typ obiektu. Jeśli jest to instancja klasy, '__dict__' jest przeszukiwany przed deskryptorami danych. Czy to prawda? – direprobs
@direprobs: co się dzieje, to rozpoczęcie wyszukiwania atrybutów na obiekcie, a Python zawsze robi 'type (object) .__ getattribute __ (object, attribute_name)'; dla obiektów klasy "typ .__ getattribute__", dla instancji "obiekt .__ getattribute__" (w obu przypadkach, o ile nie jest zdefiniowany ponownie przez podtyp/podklasę). Tak więc "sprawdzanie typu" odbywa się * przed wywołaniem * '__getattribute__'. –
Tak, zgadza się. Chodzi o to, próbowałem 'type .__ getattribute __ (A, '__class __')' który zwraca ''. Jako takie, zarówno 'type .__ getattribute__' jak i' object .__ getattribute__' uważają deskryptory danych o wyższym priorytecie niż '__dict__' dla (Classes), a nie (Instances). Ale kiedy uruchomiłem 'type .__ getattribute __ (A(), '__class __')' to zwraca '1'. Sugeruje to, że istnieje pewnego rodzaju sprawdzanie typu (czy obiekt przekazywany do '__getattribute__' jest klasą lub wystąpieniem klasy), jeśli jest to klasa, to Python najpierw szuka deskryptorów danych. –
direprobs