JavaRush /Курсы /Модуль 1: Python Core /Порядок разрешения методов (MRO)

Порядок разрешения методов (MRO)

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

11.1 Method Resolution Order

Порядок разрешения методов (Method Resolution Order, MRO) определяет последовательность, в которой Python ищет методы и атрибуты в иерархии классов. Это особенно важно при работе с множественным наследованием, когда класс может наследовать атрибуты и методы от нескольких родительских классов.

Грубо говоря, существует строгий фиксированный порядок (или, скорее, алгоритм), согласно которому Python обходит дерево наследования классов. Этот алгоритм обеспечивает корректный порядок поиска методов, который можно описать следующим образом:

Алгоритм C3-линеаризации

Алгоритм C3-линеаризации определяет MRO путем комбинирования:

  • Самого класса.
  • Списка родительских классов в порядке их перечисления.
  • MRO родительских классов в том же порядке.

Правила алгоритма C3-линеаризации

  • Сохранять локальный порядок методов: если класс A указан перед классом B, все методы класса A должны рассматриваться перед методами класса B.
  • Поддерживать порядок в родительских классах: если класс A является родителем класса B, то все методы класса A должны рассматриваться перед методами класса B.
  • Учитывать порядок наследования: если класс C является родителем для двух или более классов, порядок методов класса C должен сохраняться в MRO всех этих классов.

Шаги алгоритма:

Шаг 1. Начнем с самого класса:

Всегда начинаем с самого класса, в котором вызван метод.

Шаг 2. Добавляем базовые классы в порядке их перечисления:

После текущего класса проверяем базовые классы в том порядке, в каком они указаны при наследовании.

Шаг 3. Обходим родительские классы:

Ищем поля и методы там.

Шаг 4. Объединяем MRO родительских классов:

Если один и тот же базовый класс наследуется через несколько путей, он проверяется только один раз и в правильном порядке (все остальные разы он будет пропущен).

Для тех, кто уже знаком с темой «Алгоритмы и структуры данных», это поиск в глубину, а не в ширину.

11.2 Проверка MRO

В Python можно проверить порядок обхода методов и полей класса, используя атрибут __mro__ или функцию mro().

Пример:


class A:
    def method(self):
        print("A")
        
class B(A):
    def method(self):
        print("B")
        
class C(A):
    def method(self):
        print("C")
        
class D(B, C):
    def method(self):
        print("D")
        

# Проверка MRO
print(D.__mro__)
        

Вывод будет:


(<class '__main__.D'>, 
<class '__main__.B'>, 
<class '__main__.C'>,
<class '__main__.A'>,
<class 'object'>)
        

Это показывает порядок, в котором Python будет искать методы и атрибуты:

  • D: Python сначала проверяет метод в классе D.
  • B: Затем Python проверяет метод в классе B (первый родительский класс).
  • C: Если метод не найден в классе B, Python проверяет метод в классе C (второй родительский класс).
  • A: Если метод не найден в классах B и C, Python проверяет метод в классе A.
  • object: В конце концов, Python проверяет метод в базовом классе object.

11.3 Использование super() с MRO

Функция super() следует MRO для вызова методов родительских классов в правильном порядке. Рассмотрим пример использования super():

class A:
    def method(self):
        print("A")
        super().method()
        
class B(A):
    def method(self):
        print("B")
        super().method()
        
class C(A):
    def method(self):
        print("C")
        super().method()
        
class D(B, C):
    def method(self):
        print("D")
        super().method()
        
        
d = D()
d.method()
        

Вывод будет следующим:


D
B
C
A
        

Порядок обхода (MRO)

1. Вызов метода method класса D:

  • Python сначала проверяет метод в классе D и находит его там.
  • Метод D.method() выполняется и печатает "D".
  • Затем вызывается super().method(), который следует MRO для вызова следующего метода.

2. Вызов метода method класса B:

  • Согласно MRO, следующий класс после D — это B.
  • Метод B.method() выполняется и печатает "B".
  • Затем вызывается super().method(), который следует MRO для вызова следующего метода.

3. Вызов метода method класса C:

  • Следующий класс в MRO после B — это C.
  • Метод C.method() выполняется и печатает "C".
  • Затем вызывается super().method(), который следует MRO для вызова следующего метода.

4. Вызов метода method класса A:

  • Следующий класс в MRO после C — это A.
  • Метод A.method() выполняется и печатает "A".
  • Затем вызывается super().method(), но так как у A нет родительских методов method (кроме object), вызов завершится без дальнейших действий.
2
Задача
Модуль 1: Python Core, 9 уровень, 10 лекция
Недоступна
Использование super() и MRO
Использование super() и MRO
2
Задача
Модуль 1: Python Core, 9 уровень, 10 лекция
Недоступна
Переопределение метода
Переопределение метода
1
Опрос
Наследование, 9 уровень, 10 лекция
Недоступен
Наследование
Наследование
Комментарии (23)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Иван Уровень 16
14 января 2026
В коде ошибка, а проверку проходит, если сделать без ошибки, проверку не пройдёт. Это как так?

# Использование super() и MRO

# Создайте классы A, B, C, и D, где B и C наследуют от A, а D наследует от B и C.
# В каждом классе определите метод method, который выводит имя класса и вызывает метод super().method().
# Создайте экземпляр класса D и вызовите метод method, чтобы понять порядок вызова методов по MRO.

class A:
    def method(self):
        print("A")
        super().method()

class B(A):
    def method(self):
        print('B')
        super().method()
        
class C(A):
    def method(self):
        print('C')
        super().method()
        
class D(B,C):
    def method(self):
        print('D')
        super().method()

        
d = D()
d.method()
print(D.mro())
Blackskillow Уровень 16
14 января 2026
Тоже получил ошибку. Советуют добавить исключение, вот сделал: class A: def method(self): try: print('A') super().method() except AttributeError: print('Конец вызова') class B(A): def method(self): print('B') super().method() class C(A): def method(self): print('C') super().method() class D(B, C): def method(self): print('D') super().method() obj = D() obj.method()
Дмитрий Уровень 33
21 декабря 2025
Тупик первой задачи. 1. Если в A есть super().method() -> AttributeError, валидация не проходит 2. Если в A нет super().method() или замаскировано через if, try...except - то валит на второе условие и не засчитывает. "Правильное решение" тоже не валидируется.
tsypnyatov Уровень 23
9 ноября 2025
Задачи - дно. Хоть бы названия классов меняли, а не тупо копировали из лекции.Чисто для разнообразия. Послушал друзей, которые проходили курс по Java, что очень качественный курс. По итогу - половина задач в лекциях - просто задачи из этих же лекций. Сами статьи с ошибками, малоинформативные, особенно для тех ,кто с нуля. Если бы не очные лекции с хорошим ментором, то вернул бы деньги.
Роман Уровень 31
24 сентября 2025
4, Вызов метода method класса A: Следующий класс в MRO после C — это A. Метод A.method() выполняется и печатает "A". Затем вызывается super().method(), но так как у A нет родительских методов method (кроме object), вызов завершится без дальнейших действий. Вызов завершится ошибкой AttributeError: 'super' object has no attribute 'method'
Роман Уровень 31
24 сентября 2025
При этом, если убрать из класса A вызов super().method(), то проверка ругается, предлагая ввести дополнительный родительский класс для А. Но если оставить с ошибкой, то проверка проходит))
Леонид Уровень 17
25 августа 2025
А это адекватно, что GPT на 3 вопрос сказало, что верного ответа из предложенных вариантов вообще нет...?
shinobi Уровень 19
10 августа 2025
Даже не стал читать задание первой задачи, просто скопировать весь код из лекции ничего не меняю, вставляю в ответ, проверяю - и вуаля, идеальное решение. Классная практика, ребята, круто, что взяли деньги за это
Ruzimat Уровень 15
3 августа 2025
Авторы курса сделайте уже обновление и исправьте ошибки. Раньше работали за качество а сейчас курсы делают только на количество. Уже все пишут что ошибки везде, но нет реакция со стороны JavaRush. Какой курс был Java проект, а это вообще без понятие лекции, с многими ошибками. Деньги же брали значить надо же как то работать с ошибками.
Slevin Уровень 64
3 июля 2025
Лекция нормальная, задания - копии друг друга и копии заданий из прошлой лекции. Практически - мы наблюдаем как задания наследуют друг друга с минимальными изменениями!
Slevin Уровень 64
3 июля 2025
Может уже стоит перестать в примерах (и в описании задания) вызывать " super().method()" у класса, у которого родительским является класс object? У класса 'A' нет родительского класса в привычном понимании
Mr.Robot Уровень 21 Expert
13 марта 2025
Поаккуратнее со второй задачей ) Похоже, валидатор уже переделали, а условие поменять забыли... Все из-за злосчастного вызова super().action() в родительском классе M. Как тут правильно писали из-за этого возникает ошибка при выполнении кода. Однако первая задача прошла валидатор несмотря на эту ошибку, а вторая - проходит валидацию, только если убрать super().action() из M класса.