В Python 2 с трюком можно создать класс с несколькими базами, хотя базы имеют метаклассы, которые являются не подклассами друг друга.Возможно ли динамическое создание метакласса для класса с несколькими базами в Python 3?
Фокус в том, что эти метаклассы сами по себе являются метаклассами (назовите это «метаметаклас»), и этот метаметалкласс предоставляет метаклассы методу вызова, который при необходимости динамически создает общий подметалкласс базовых метаклассов. В конце концов, результаты класса, чей метакласс является новым суб-метаклассом. Вот код:
>>> class MetaMeta(type):
... def __call__(mcls, name, bases, methods):
... metabases = set(type(X) for X in bases)
... metabases.add(mcls)
... if len(metabases) > 1:
... mcls = type(''.join([X.__name__ for X in metabases]), tuple(metabases), {})
... return mcls.__new__(mcls, name, bases, methods)
...
>>> class Meta1(type):
... __metaclass__ = MetaMeta
...
>>> class Meta2(type):
... __metaclass__ = MetaMeta
...
>>> class C1:
... __metaclass__ = Meta1
...
>>> class C2:
... __metaclass__ = Meta2
...
>>> type(C1)
<class '__main__.Meta1'>
>>> type(C2)
<class '__main__.Meta2'>
>>> class C3(C1,C2): pass
...
>>> type(C3)
<class '__main__.Meta1Meta2'>
Этот пример (конечно, изменяя синтаксис для class C1(metaclass=Meta1)
и т.д.) не работает в Python 3.
Вопрос 1: Правильно ли я понимаю, что в Python 2, первый C3
построен с использованием метакласса первой базы, и ошибка будет возникать только в том случае, если type(C3)
не являются общим подклассом type(C1)
и type(C2)
, тогда как в Python 3 ошибка возникает ранее?
Вопрос 2: (Как) Возможно ли, чтобы приведенный выше пример работал в Python 3? Я попытался использовать подкласс abc.ABCMeta
в качестве метаметаллов, но даже если использование пользовательского __subclasscheck__
приведет к возврату issubclass(Meta1, Meta2)
True
, создание C3 все равно приведет к ошибке.
Примечания: Конечно, я мог бы сделать Python 3 счастливым статический определяя Meta1Meta2
и явно использовать его в качестве метакласса для C3
. Однако этого я не хочу. Я хочу, чтобы общий суб-метакласс был создан динамически.
Это немного похоже на сложность для создания сложных вещей :-). Почему вы хотите сделать это вместо более простого для чтения и понимания варианта, где вы создаете новый метакласс для 'C3', смешивая метаклассы C1 и CF2 явно? – mgilson
Я разработчик SageMath, языком пользователя которого в настоящее время является Python 2.7. В этом CAS используются разные метаклассы, реализующие отдельные функции. Скажем, пять функций, что означает, что существует 32 возможных сочетания функций. Немного неудобно статически определять каждую возможную комбинацию, и на самом деле SageMath в настоящее время предоставляет только * некоторые * комбинации. Кроме того, создание новых классов должно быть легким для пользователя: пользователю не нужно будет искать метаклассы всех баз и явно выбирать правильный комбинированный метакласс. –