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

Несоответствие множественного наследования метакласса

Почему это:

class MyType(type):
    def __init__(cls, name, bases, attrs):
        print 'created', cls
class MyMixin:
    __metaclass__ = MyType
class MyList(list, MyMixin): pass

в порядке и работает как ожидалось:

created <class '__main__.MyMixin'>
created <class '__main__.MyList'>

Но это:

class MyType(type):
    def __init__(cls, name, bases, attrs):
        print 'created', cls
class MyMixin:
    __metaclass__ = MyType
class MyObject(object, MyMixin): pass

Не все в порядке и взрывается таким образом?:

created <class '__main__.MyMixin'>
Traceback (most recent call last):
  File "/tmp/junk.py", line 11, in <module>
    class MyObject(object, MyMixin): pass
TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution
order (MRO) for bases object, MyMixin
4b9b3361

Ответ 1

Это не проблема пользовательского метакласса (хотя он был диагностирован на стадии метакласса):

>>> class Normal(object): pass
... 
>>> class MyObject(object, Normal): pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution
order (MRO) for bases object, Normal

и проблема такая же, как и эта:

>>> class Derived(Normal): pass
... 
>>> class Ok(Derived, Normal): pass
... 
>>> class Nope(Normal, Derived): pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution
order (MRO) for bases Normal, Derived

i.e., не может умножать наследование из базового класса, за которым следует производный класс, - невозможно определить согласованный MRO, который удовлетворяет обычным ограничениям/гарантиям MRO.

К счастью, вы не хотите этого делать - подкласс предположительно переопределяет некоторый метод базового класса (что нормальные подклассы делают;-) и имеющий базовый класс "впереди" означает "затенение переопределения" прочь".

Помещение базового класса после производного одного из них довольно бесполезно, но по крайней мере оно безобидно (и соответствует нормальным гарантиям MRO).

Ваш первый пример, конечно, работает, потому что MyMixin не получен из list:

>>> MyMixin.__mro__
(<class '__main__.MyMixin'>, <type 'object'>)

... но он получен из object (как и каждый класс Python в современном стиле), поэтому второй пример не может работать (совершенно независимо от MyMixin с пользовательским метаклассом).

Ответ 2

Здесь вы наследуете родительский класс, а родительский класс уже наследует другой класс, поэтому нет необходимости наследовать класс, который родительский класс уже унаследовал.

Например:

class A(object):
.
.
class B(object, A):
.
.

Он выдает ошибку, поскольку A наследует класс Object и B наследует A, поэтому косвенно B наследует объект, поэтому нет необходимости наследовать объект. , , .

Решение состоит в том, чтобы просто удалить класс объекта из списка аргументов класса B.