MRO и super при множественном наследовании
Вопрос
Объясните, как Python ищет методы при множественном наследовании и как работает super().
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
MRO строится C3-линеаризацией, видно в `Class.__mro__`
Потомок раньше предков, порядок родителей из объявления сохраняется
`super()` вызывает следующий класс в MRO объекта, а не прямого родителя
Кооперативное наследование: каждый метод вызывает `super()`, принимает `**kwargs`
Ромб: каждый метод выполняется один раз
Если линеаризация невозможна, `TypeError` при создании класса
Что могут спросить следом
- Что такое миксины и где вы их видели?
- Чем
super().__init__()лучшеParent.__init__(self)?
Разбор
Образцовый ответ: «При множественном наследовании порядок поиска атрибутов задаёт MRO, его видно в D.__mro__. Строится он алгоритмом C3-линеаризации с двумя гарантиями: класс всегда раньше своих родителей, и порядок родителей из объявления сохраняется. Для ромба D(B, C), где оба наследуют A, получится D, B, C, A, object. Если такой порядок построить нельзя, например родители перечислены в противоречивом порядке, Python бросит TypeError прямо при создании класса. super() возвращает прокси, который ищет метод в MRO типа текущего объекта, начиная со следующего после текущего класса. Поэтому из B вызов super().save() уйдёт в C, а не в A, если объект класса D. Чтобы это работало, наследование должно быть кооперативным: каждый метод в цепочке вызывает super() и пропускает лишние аргументы через **kwargs. Тогда каждый метод выполнится ровно один раз. Если вместо этого звать A.__init__(self) явно, в ромбе A инициализируется дважды. На практике это нужно для миксинов, например в Django class-based views: LoginRequiredMixin ставят левее основного view».
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Предыдущий вопрос
dataclass, NamedTuple или Pydantic
Следующий вопрос
Что на самом деле вызывает super()