Порядок вывода: Base, Y, X, Z. Поиск super идёт по MRO Z → X → Y → Base, а печать происходит при возврате из вложенных вызовов.
Поведение конструкторов при множественном наследовании
Порядок вывода: Base, Y, X, Z. Поиск super идёт по MRO Z → X → Y → Base, а печать происходит при возврате из вложенных вызовов.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Разъясните, как будет происходить инициализация при создании экземпляра класса Z, учитывая порядок вызовов super() и схему наследования Z(X, Y).
class Base:
def __init__(self):
print('Base')
class X(Base):
def __init__(self):
super().__init__()
print('X')
class Y(Base):
def __init__(self):
super().__init__()
print('Y')
class Z(X, Y):
def __init__(self):
super().__init__()
print('Z')
Z()
Ответ
Порядок вывода: Base, Y, X, Z. Поиск super идёт по MRO Z → X → Y → Base, а печать происходит при возврате из вложенных вызовов.
При входе в Z.__init__ вызывается X.__init__. Его super() для экземпляра Z продолжает цепочку не напрямую в Base, а в Y. Затем Y вызывает Base.
Base
Y
X
Z
После печати Base управление возвращается в Y, затем в X и Z. Общий предок инициализируется один раз. Это работает благодаря согласованному использованию super() всеми участниками цепочки. Прямые вызовы Base.__init__(self) из обеих ветвей могли бы привести к повторной инициализации и нарушить кооперативное наследование.