Практика множественного наследования
Python позволяет классу наследовать от более чем одного родительского класса. Это называется множественным наследованием (multiple inheritance). Оно может быть мощным инструментом для объединения функциональности из разных источников, но также вносит сложность, особенно в том, как Python решает, какой метод родителя использовать, если у них одинаковые имена.
Этот порядок поиска называется Порядком разрешения методов (Method Resolution Order, MRO). Python использует алгоритм, называемый линеаризацией C3, для определения согласованного и предсказуемого MRO.
Давайте рассмотрим это на новом примере. Откройте файл multiple_inheritance.py в проводнике файлов и добавьте следующий код:
## File: multiple_inheritance.py
class ParentA:
def speak(self):
print("Speaking from ParentA")
def common_method(self):
print("ParentA's common method")
class ParentB:
def speak(self):
print("Speaking from ParentB")
def common_method(self):
print("ParentB's common method")
## Child наследуется от A, затем от B
class Child_AB(ParentA, ParentB):
pass
## Child наследуется от B, затем от A
class Child_BA(ParentB, ParentA):
def common_method(self):
print("Child_BA's own common method")
if __name__ == "__main__":
child1 = Child_AB()
child2 = Child_BA()
print("--- Investigating Child_AB (ParentA, ParentB) ---")
child1.speak()
child1.common_method()
## Метод .mro() показывает Порядок разрешения методов
print("MRO for Child_AB:", [c.__name__ for c in Child_AB.mro()])
print("\n--- Investigating Child_BA (ParentB, ParentA) ---")
child2.speak()
child2.common_method()
print("MRO for Child_BA:", [c.__name__ for c in Child_BA.mro()])
Сохраните файл. Здесь Child_AB наследуется от ParentA, а затем от ParentB. Child_BA наследуется в обратном порядке. Когда вызывается метод, Python ищет его в порядке, указанном MRO.
Запустите скрипт из терминала:
python multiple_inheritance.py
Вы увидите следующий вывод:
--- Investigating Child_AB (ParentA, ParentB) ---
Speaking from ParentA
ParentA's common method
MRO for Child_AB: ['Child_AB', 'ParentA', 'ParentB', 'object']
--- Investigating Child_BA (ParentB, ParentA) ---
Speaking from ParentB
Child_BA's own common method
MRO for Child_BA: ['Child_BA', 'ParentB', 'ParentA', 'object']
Из вывода вы можете заметить:
child1.speak() вызывает метод из ParentA, потому что ParentA идет первым в MRO Child_AB.
child2.speak() вызывает метод из ParentB, потому что ParentB идет первым в MRO Child_BA.
child2.common_method() вызывает версию, определенную непосредственно в Child_BA, так как Python находит ее там в первую очередь, прежде чем проверять родителей.
Понимание MRO имеет решающее значение для прогнозирования поведения в сценариях множественного наследования.