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
Недоступний
Наслідування
Наслідування
Коментарі (9)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Сергій Рівень 20
8 серпня 2026
Завдання "Використання super() і MRO" - не може бути логічно виконано та пройти перевірку автоботом. Через те що клас А це найвищий клас, то виклик super().method() дає помилку. Якщо зробити наслідування для А від іншого класу - порушується ієрархія і тест не проходить. При спробі включити перевірку трай-ексепт для методу super().method() в класі А, ші його "не бачить" і просто не зараховує спробу. Правильне рішення із підказки не має super().method() в класі А і теж не проходить перевірку. ЛАЙФХАК: щоб пройти це завдання просто треба задовбати автобота - одне і теж рішення давати на перевірку багато разів і він здасться. На цю задачу витратив 9 спроб, 5 з яких були з super().method() в класі А і все вийшло. Вже не перший раз стикаюсь з такими карявими завданнями на цій платформі. Колись одне завдання, теж з помилковою умовою, здав за 13 спроб, в кінці постійно підсовуюючи одне і те саме рішення.
Дмитро Рівень 56
28 січня 2026
Так проходить class A(): def method(self): print("Name A") try: super().method() except AttributeError: pass class B(A): def method(self): print("Name B") super().method() class C(A): def method(self): print("Name C") super().method() class D(B, C): def method(self): print("Name D") super().method() d = D() d.method()
Oleksandr Рівень 21
15 травня 2025
Що таке "C3-лінеризація" ? Бракує визначення в лекції
negoda Рівень 31
12 серпня 2025
C — означает "consistent" 3 — потому что алгоритм объединяет (линеаризует) три источника информации при построении порядка: Линеаризацию каждого из родителей (их MRO) Прямой список родителей (то, что указано при объявлении класса) Сам класс, для которого строится MRO
Nataliia Fedyshyn Рівень 1
19 січня 2025

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 Traceback (most recent call last): File "/Users/fedytion/javarush/3538753/javarush-project/src/ua/javarush/python/core/level09/task16/task16.py", line 31, in <module> d.method() File "/Users/fedytion/javarush/3538753/javarush-project/src/ua/javarush/python/core/level09/task16/task16.py", line 27, in method super().method() File "/Users/fedytion/javarush/3538753/javarush-project/src/ua/javarush/python/core/level09/task16/task16.py", line 17, in method super().method() File "/Users/fedytion/javarush/3538753/javarush-project/src/ua/javarush/python/core/level09/task16/task16.py", line 22, in method super().method() File "/Users/fedytion/javarush/3538753/javarush-project/src/ua/javarush/python/core/level09/task16/task16.py", line 12, in method super().method() ^^^^^^^^^^^^^^ AttributeError: 'super' object has no attribute 'method' І ніхто не пояснює чому.. Навіщо давати в приклад код з помилками? 😬
Nataliia Fedyshyn Рівень 1
19 січня 2025
Я вже розібралась чому помилка, не можна викликати метод super() в "головного" батьківського класу, бо він не може сам собі бути батьківським класом. Але все ж, це збиває з пантелику. Виправте, будь ласка і уточніть в лекції це.
Василь Рівень 64
8 квітня 2025
У будь якокго класу батьківським є object. В наведеному прикладі в класу A є зайвим виклик super().method() тому що він і викликає клас object в якому немає методу method() ось тому і помилка. Правильніше переписати клас А: class A: def method(self): print("A")
Дмитро Рівень 31
23 квітня 2025
Досі не виправили, ще і помилку видає (при перевірці) коли class A: def method(self): print("A") #super().method() А у відповіді class A: def method(self): print("A") # No call to super() because A is the topmost class Таки вказано що не потрібно викликати super() Чекаємо коли виправлять автоматичну перевіку)
Vira Рівень 64
8 січня 2026
class W: def method(self): pass class A(W): 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() так проходить перевірку, бо всі умови виконані