10.1 Наследование от нескольких классов
Множественное наследование в Python позволяет классу наследовать атрибуты и методы от более чем одного родительского класса. Это даёт большую гибкость и позволяет повторно использовать код, но также может привести к сложным иерархиям и потенциальным конфликтам.
Возможность перечислить своему классу пять родителей значительно расширяет ваши возможности и делает написание кода очень удобным. Сделать это очень просто — нужно просто перечислить классы-родители через запятую:
class Base1:
def method1(self):
print("Method1 from Base1")
class Base2:
def method2(self):
print("Method2 from Base2")
class Derived(Base1, Base2):
pass
obj = Derived()
obj.method1()
obj.method2()
Всё работает так, как и планировалось — красота.
Однако у множественного наследования есть несколько сложных сторон, которые обязательно нужно учитывать при его использовании. Давайте рассмотрим, как это работает и как избегать проблем, связанных с множественным наследованием.
10.2 Вызов метода, который есть у нескольких базовых классов
Класс может наследовать атрибуты и методы от нескольких родительских классов, перечисленных в скобках после имени класса. И эти атрибуты и методы могут иметь одинаковые названия:
class Base1:
def method(self):
print("Method from Base1")
class Base2:
def method(self):
print("Method from Base2")
class Derived(Base1, Base2):
pass
obj = Derived()
obj.method() # чей метод тут вызовется?
В этом примере Derived класс наследуется от Base1 и Base2. Когда вызывается method(), Python выберет метод первого указанного класса — Base1.
Но это не так очевидно, не так ли? И если кто-то изменит код базового класса, может пострадать вся логика приложения, и вы даже не узнаете, что что-то не так. Просто начнут вызываться немного не те методы :)
10.3 Использование super() с множественным наследованием
Ещё одна интересная особенность — это вызов super() для базового класса при множественном наследовании.
Пример:
class Base1:
def method(self):
print("Method from Base1")
super().method()
class Base2:
def method(self):
print("Method from Base2")
super().method()
class Derived(Base1, Base2):
def method(self):
print("Method from Derived")
super().method()
obj = Derived()
obj.method()
Ну что? Какой будет вывод на экран?
Method from Derived
Method from Base1
Или
Method from Derived
Method from Base2
У меня для вас сюрприз — вывод будет таким:
Method from Derived
Method from Base1
Method from Base2
Код super().method() вызовет метод method() у каждого базового класса! Это как раз и есть те самые нюансы, о которых я говорил при первом упоминании множественного наследования.
10.4 Ромбовидное (Diamond) наследование
И наконец, классическая проблема ромбовидного наследования. Её легче показать на примере, чем описывать:
В виде кода это может выглядеть, например, так:
class A:
def method(self):
print("Method from A")
class B(A):
def method(self):
print("Method from B")
super().method()
class C(A):
def method(self):
print("Method from C")
super().method()
class D(B, C):
def method(self):
print("Method from D")
super().method()
obj = D()
obj.method()
Вывод будет таким:
Method from D
Method from B
Method from C
Method from A
Чтобы хоть как-то ориентироваться в множественном наследовании, вам нужно хорошо знать, в каком порядке Python ищет поля и методы у родительских классов. Именно об этом вы узнаете в следующей лекции.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ