Множественное наследование и вызов super()

Я получаю сообщение об ошибке: TypeError: __init__() принимает ровно 2 аргумента (дано 3)

При попытке создать экземпляр объекта из класса Top:

super (Middle1, self).__ init __ (name, "middle")

class Base(object):
    def __init__(self, name, type):
        pass

class Middle1(Base):
    def __init__(self, name):
        super(Middle1, self).__init__(name, "middle1")

class Middle2(Base):
    def __init__(self, name):
        super(Middle2, self).__init__(name, "middle2")

class Middle3(Base):
    def __init__(self, name):
        super(Middle3, self).__init__(name, "middle3")

class Top(Middle1, Middle2, Middle3):
    def __init__(self):
        super(Top, self).__init__("top")

# Here is where it produces the error
if __name__ == '__main__':
    Top()

Что я не понимаю в этой проблеме множественного наследования?

Примечание: это Python 2.7

РЕДАКТИРОВАТЬ

Итак, я попробовал кое-что, что я думаю, работает для моего случая. Это равносильный конечный результат, я думаю, что он в первую очередь форсирует глубину, не вызывая super и вызывая каждый отдельный __init__ вместо этого.

class Base(object):
    def __init__(self, name, type):
        pass

class Middle1(Base):
    def __init__(self, name, type = "middle1"):
        super(Middle1, self).__init__(name, type)

class Middle2(Base):
    def __init__(self, name, type = "middle2"):
        super(Middle2, self).__init__(name, type)

class Middle3(Base):
    def __init__(self, name, type = "middle3"):
        super(Middle3, self).__init__(name, type)

class Top(Middle1, Middle2, Middle3):
    def __init__(self):
        Middle1.__init__(self, "top")
        Middle2.__init__(self, "top")
        Middle3.__init__(self, "top")

# No errors anymore
if __name__ == '__main__':
    Top()

2 ответа

Решение

Во-первых, вы должны посмотреть на порядок разрешения метода Top:

>>> for c in Top.__mro__: print c
...
<class '__main__.Top'>
<class '__main__.Middle1'>
<class '__main__.Middle2'>
<class '__main__.Middle3'>
<class '__main__.Base'>
<type 'object'>

Это поможет вам увидеть, к какому классу относится каждый звонок super представляет собой.

Ваша ошибка в том, что вы считаете super(Middle1, self) относится к (только) базовому классу Base из Middle1, Это не так: это относится к классу, следующему Middle1 в MRO self.__class__, поскольку self.__class__ является Topследующий класс в строке Middle2, чья __init__ принимает только один аргумент

Использовать super правильно из метода вы должны убедиться, что метод принимает одинаковые аргументы в каждом классе, потому что вы не можете предсказать, какой метод класса будет вызван, посмотрев на сам код; это полностью зависит от типа объекта, который инициирует цепочку вызовов, который может быть классом, о котором вы даже не знаете.

Есть два поста, которые я предлагаю прочитать:

Вместе они дают вам хорошее понимание того, когда super можно правильно использовать и как избежать проблемы, которую вы видите здесь.

(В полном раскрытии я недавно не читал ни одного поста, поэтому воздержусь от попыток обобщить рекомендации, представленные в каждом.)

Как именно вы создаете экземпляры Top объектов?

Учитывая ваш код выше, следующее работает нормально:

   topObj = Top()
   middleObj = Middle("middle")
   baseObj = Base("base", "type")
Другие вопросы по тегам