Подтвердить что ты не робот

Python - объект может быть своего собственного типа?

Я играл с метаклассами в CPython 3.2.2, и я заметил, что можно закончить класс, который является его собственным типом:

Python 3.2.2 (default, Sep  5 2011, 21:17:14) 
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class MC(type):            #a boring metaclass that works the same as type
...     pass
... 
>>> class A(MC, metaclass=MC): #A is now both a subclass and an instance of MC...
...     pass
...
>>> A.__class__ = A            #...and now A is an instance of itself?
>>> A is type(A)
True

Для нашего метакласса A на самом деле нет различий между атрибутами класса и экземпляра:

>>> A.__next__ = lambda self: 1
>>> next(A)
1                                     #special method lookup works correctly
>>> A.__dict__
dict_proxy({'__module__': '__main__',
'__next__': <function <lambda> at 0x17c9628>,
'__doc__': None})
>>> type(A).__dict__
dict_proxy({'__module__': '__main__',
'__next__': <function <lambda> at 0x17c9628>,
'__doc__': None})                                #they have the same `__dict__`

Все это работает одинаково (кроме изменения на __metaclass__ и __next__ не являющегося специальным методом) в CPython 2.7.2, PyPy 1.6.0 (который реализует Python 2.7.1) и Jython 2.2. 1 (не знаю, какая версия Python, если таковая имеется, - я не очень хорошо знаком с Jython).

Я не могу найти много объяснений относительно условий, при которых допускается присвоение __class__ (видимо, соответствующие типы должны определяться пользователем и иметь какой-то аналогичный макет в некотором смысле?). Обратите внимание, что A должен быть как подклассом, так и экземпляром MC для выполнения задания __class__. Являются ли рекурсивные иерархии метакласса, как это, действительно, приемлемыми? Я очень смущен.

4b9b3361

Ответ 1

Рекурсивные иерархии метакласса на самом деле являются частью ядра языка:

>>> type(type)
<class 'type'>

Таким образом, даже стандартный метакласс type является его собственным типом. Нет концептуальной проблемы с этой конструкцией - это просто означает, что атрибут __class__ класса указывает на сам класс.

Назначения атрибуту __class__ разрешены только для пользовательских классов. Назначение является законным, если либо исходный класс, и новый класс не определяют __slots__, либо оба устанавливают __slots__ в одну и ту же последовательность.