Наследование метаклассов в Python 2 и Python 3

#python #django #oop #inheritance #metaclass

#python #django #ооп #наследование #метакласс

Вопрос:

У меня есть следующий пример кода для Python 2.7:

 class MetaA(type):

    def __new__(cls, name, bases, attrs):
        print('MetaA::__new__')
        print('CLS:'   str(cls))
        print('Name:'   name)
        print('============================')
        return super(MetaA, cls).__new__(cls, name, bases, attrs)


class A(object):
    __metaclass__ = MetaA


class MetaB(type(A)):
    pass


class SomeMixin(A):
    pass


class B(A):
    __metaclass__ = MetaB


class C(SomeMixin, B):
    pass
  

После его выполнения у меня есть такой вывод:

 MetaA::__new__
CLS:<class '__main__.MetaA'>
Name:A
============================
MetaA::__new__
CLS:<class '__main__.MetaA'>
Name:SomeMixin
============================
MetaA::__new__
CLS:<class '__main__.MetaB'>
Name:B
============================
MetaA::__new__
CLS:<class '__main__.MetaA'>
Name:C
============================
MetaA::__new__
CLS:<class '__main__.MetaB'>
Name:C
============================
  

Дело в том, что при class C определении сначала вызывается метод __new__ для метакласса MetaA (базового), а затем для метакласса MetaB вызывается.

Если я изменю порядок смешивания и унаследую класс в своем классе C следующим образом

 class C(B, SomeMixin):
  

результат следующий:

 MetaA::__new__
CLS:<class '__main__.MetaA'>
Name:A
============================
MetaA::__new__
CLS:<class '__main__.MetaA'>
Name:SomeMixin
============================
MetaA::__new__
CLS:<class '__main__.MetaB'>
Name:B
============================
MetaA::__new__
CLS:<class '__main__.MetaB'>
Name:C
============================
  

Метод __new__ для метакласса MetaA в этом случае не вызывается, только для метакласса MetaB .

Если я выполню почти тот же код в Python 3, несмотря на порядок наследования в class C , метод __new__ будет вызван только для метакласса MetaA .

Не мог бы кто-нибудь объяснить, почему это происходит и что было изменено в Python 3 с точки зрения такого поведения?

Спасибо!