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