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 шукає поля та методи у батьківських класів. Саме про це ви дізнаєтеся у наступній лекції.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ