Проблема ромба
Второй пример спектра проблем, которые могут возникнуть в результате множественного наследования, иллюстрируется классической проблемой под названием проблема ромба. Название отражает форму диаграммы наследования - взгляните на картинку:

- есть самый верхний суперкласс с именем A;
- есть два подкласса, производных от A: B и C;
- а также самый нижний подкласс с именем D, производный от B и C (или C и B, поскольку эти два варианта означают разные вещи в Python).
Видите ромб?
Посмотрите на код в редакторе. Та же структура, но выраженная на Python.
Некоторые языки программирования вообще не допускают множественное наследование, и, как следствие, они не позволяют построить ромб - это путь, который Java и C# выбрали с момента своего возникновения.
Однако Python выбрал другой путь - он допускает множественное наследование, и он не возражает, если Вы пишете и запускаете код, подобный тому, который находится в редакторе. Но не забывайте про MRO - он всегда важен.
Давайте перестроим наш пример с предыдущей страницы, чтобы сделать его более похожим на ромб, как показано ниже:
Примечание: оба класса Middle
определяют метод с тем же именем: m_middle()
.
Это вносит небольшую неопределенность в наш образец, хотя мы абсолютно уверены, что Вы можете ответить на следующий ключевой вопрос: какой из двух методов m_middle()
действительно будет вызван при выполнении следующей строки?
Другими словами, что Вы увидите на экране: middle_left
или middle_right
?
Вам не нужно торопиться - подумайте дважды и помните о MRO в Python!
Готовы?
Да, Вы правы. Вызов активирует метод m_middle()
, который происходит от класса Middle_Left
. Объяснение простое: класс указан перед Middle_Right
в списке наследования класса Bottom
. Если Вы хотите убедиться, что в этом нет никаких сомнений, попробуйте поменять местами эти два класса в списке и проверьте результаты.
Если Вы хотите получить более глубокие впечатления о множественном наследовании и ромбах, попробуйте изменить наш фрагмент и оснастить класс Upper
другим экземпляром метода m_middle()
, и внимательно исследуйте его поведение.
Как видите, ромбы могут принести в Вашу жизнь некоторые проблемы - как настоящие, так и те, которые предлагает Python.
Code
class A:pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
d = D()