← Назад к вопросам

Что такое Method Resolution Order в Python 2?

2.7 Senior🔥 151 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Method Resolution Order (MRO) в Python 2

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

В Python 2 было два алгоритма MRO

1. Depth-First Search (DFS) - старый алгоритм

Для старых классов (не наследующих от object), Python использовал простой depth-first алгоритм:

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):
    pass

# MRO: D -> B -> A -> C -> A
# Проблема: A появляется дважды!
obj = D()
obj.method()  # Вывод: B

Этот алгоритм был неудачным, потому что:

  • Нарушал принцип монотонности (базовый класс не может появиться раньше, чем его производные)
  • Мог привести к неожиданному поведению
  • Был неинтуитивен при сложном наследовании

2. C3 Linearization - новый алгоритм для new-style классов

Для классов, наследующих от object (new-style classes), использовался более сложный алгоритм C3:

class A(object):
    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):
    pass

# MRO в Python 2: D, B, C, A, object
obj = D()
obj.method()  # Вывод: B

print(D.__mro__)  # Показывает MRO
# (<class D>, <class B>, <class C>, <class A>, <class object>)

Алгоритм C3 Linearization

Алгоритм работает по следующему принципу:

  1. Список наследования: берем порядок, в котором указаны базовые классы в определении класса
  2. Слияние (merge): объединяем списки MRO всех базовых классов и сам класс
  3. Выбор первого: выбираем первый класс, который является head и не встречается в tail других списков
  4. Рекурсия: повторяем процесс до полного слияния

Пример C3 слияния

class A(object):
    pass

class B(object):
    pass

class C(object):
    pass

class D(A, B):
    pass

class E(B, C):
    pass

class F(D, E, C):
    pass

# Расчет MRO для F:
# 1. L[F] = F + merge(L[D], L[E], L[C], [D, E, C])
# 2. L[D] = D + merge(L[A], L[B], [A, B])
# 3. L[D] = D + A + B + object
# 4. L[E] = E + merge(L[B], L[C], [B, C])
# 5. L[E] = E + B + C + object
# 6. L[F] = F + merge([D, A, B, object], [E, B, C, object], [C], [D, E, C])
# 7. L[F] = F + D + E + A + B + C + object

print(F.__mro__)
# (<class F>, <class D>, <class E>, <class A>, <class B>, <class C>, <class object>)

Практическое применение

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

MRO особенно важна при работе с super():

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

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

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

class D(B, C):
    pass

obj = D()
obj.method()
# Вывод:
# B
# C
# A

Без правильного понимания MRO код с super() может работать не так, как ожидается.

Важные отличия Python 2 и Python 3

Python 2

  • Старые классы используют DFS (это как наследование без object)
  • New-style классы используют C3
  • Нужно явно наследовать от object
# Python 2
class OldStyle:  # DFS
    pass

class NewStyle(object):  # C3
    pass

Python 3

  • Все классы автоматически новые (наследуют от object)
  • Все используют C3 алгоритм
  • Нет проблемы с DFS
# Python 3
class MyClass:  # Автоматически наследует от object, использует C3
    pass

Проверка MRO в коде

# Способ 1: атрибут __mro__
print(MyClass.__mro__)

# Способ 2: метод mro()
print(MyClass.mro())

# Способ 3: встроенная функция
print(dir(MyClass))

Когда MRO может быть проблемой

  1. Неправильный порядок наследования: если вы указали базовые классы в неправильном порядке
  2. Глубокая иерархия: когда много уровней наследования и сложное множественное наследование
  3. Конфликт методов: когда несколько базовых классов имеют одноименные методы

Заключение

MRO в Python 2 - это ключевой механизм, который управляет поведением множественного наследования. Понимание алгоритма C3 помогает писать корректный код с наследованием и использованием super(). Хотя Python 2 уже снят с поддержки, знание MRO остается полезным для понимания как работает наследование в Python 3, которое использует C3 для всех классов по умолчанию.

Что такое Method Resolution Order в Python 2? | PrepBro