JavaRush /Курсы /Модуль 1: Python Core /Множественное наследование

Множественное наследование

Модуль 1: Python Core
9 уровень , 9 лекция
Открыта

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 ищет поля и методы у родительских классов. Именно об этом вы узнаете в следующей лекции.

2
Задача
Модуль 1: Python Core, 9 уровень, 9 лекция
Недоступна
Базовые классы.
Базовые классы.
2
Задача
Модуль 1: Python Core, 9 уровень, 9 лекция
Недоступна
Супер-экшен.
Супер-экшен.
Комментарии (32)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Mongoose Уровень 25
6 июня 2026
10.3.... У меня для вас сюрприз, вывод будет таким: Method from Derived Method from Base1 Method from Base2 AttributeError: 'super' object has no attribute 'method' on line 9 (сюрпрайз маза фака).
Pan Game Уровень 64
16 мая 2026
Сложна, много ли в реальности пользуются такими запутаными наследованиями? пока что вообще упрощения не вижу в коде с таким подходом.
Mongoose Уровень 25
6 июня 2026
Это не сложна, сложна, когда тоже самое, но через лямбда функции будут давать...
EvgenyXIV Уровень 31
14 апреля 2026
В примере п.10.3 ошибка. Метод super() надо убрать из класса Base2, так как Base2 последний в кортеже базовых классов у класса Derived. Почему (Игорь Черных кратко объяснил причину - теперь чуть подробней): Метод super() при использовании множественного наследования линеаризует поиск "родительского" метода method() сначала в порядке следования базовых классов в кортеже родителей, а далее, поднимаясь в иерархическом порядке "дети" -> "родители" (или по-другому "класс" -> "базовый класс" . Конец поиска это общий для экземпляров всех классов класс object. Порядок поиска (MRO) метода method() задаётся кортежем базовых классов при первом вызове метода super(). Кортеж базовых классов для поиска метод super() получает при первом вызове метода method() из класса Derived, т.е. это (Base1, Base2) и вызывает метод method() из класса Base1. При следующем вызове (при работе метода method() в классе Base1) метод super() согласно кортежу поиска идёт в класс Base2 и вызывает из него метод method(). При следующем вызове (при работе метода method() в классе Base2) метод super() ищет метод method() в родительском (базовом) классе для класса Base2, т.е. в классе object, и выдаёт ошибку AttributeError: 'super' object has no attribute 'method', так как такого метода у класса object нет.
Игорь Черных Уровень 25
27 марта 2026
Если кто не понял "Использование super() с множественным наследованием", из-за кривоватого объяснения: встроенная функция super() вызывает не "родительский класс", а следующий класс по MRO. В указанном примере он такой: Derived - Base1 - Base2 -object Итак в Derived идет вызов super().method(), он дергает метод из Base1 и ВСЁ, в Base1 есть свой вызов super().method(), далее по MRO Base2, оттуда и берет, у Base2 тоже есть свой вызов super().method(), но у класса object такого нет, финал
Dmitriy Уровень 24
11 февраля 2026

if hasattr(super(), "describe"):
    super().describe()
либо делать заглушку для MRO в Base2, убрав super
Анатолий Уровень 63
3 февраля 2026
❤️
Anonymous #980144 Уровень 31
12 декабря 2025
"Код super().method() вызовет метод method() у каждого базового класса!" Это утверждение в общем виде неверно, т. к. super().method() вызывает method() только у следующего класса в MRO. Утверждение верно только для конкретного примера, потому что в методе каждого класса иерархии явно вызывается super().method(). И, как уже тут писали, в стр. 9 будет ошибка, потому что следующий по MRO - класс Object, у которого такого метода нет.
Maksym Уровень 22
2 ноября 2025
A где задачи на Ромбовидное (Diamond) наследование?
Mikhail Уровень 26
27 сентября 2025
Мда... Просто лучшая лекция и практика!
Sergey Уровень 1
27 августа 2025
Просто нет слов , это дно