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

Какое изменение произошло при переходе из MRO2 в MRO3?

3.0 Senior🔥 71 комментариев
#Python Core#Архитектура и паттерны

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

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

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

# Переход из MRO2 в MRO3

Что такое MRO

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

MRO2 (старый алгоритм, Python < 2.3)

В Python 2.2 и ранее использовался алгоритм DFS (Depth-First Search) для разрешения порядка методов:

class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass

# MRO2 порядок: D -> B -> A -> C -> A (проблема!)
# A посещается дважды - несоответствие логике наследования

Проблемы MRO2:

  • Дублирование базового класса: базовый класс посещался несколько раз в цепочке
  • Нарушение монотонности: порядок в MRO не совпадал с порядком в объявлении наследования
  • Неинтуитивное поведение: разработчикам было сложно предсказать, какой метод будет вызван

MRO3 (современный алгоритм, Python ≥ 2.3) — C3 Linearization

Начиная с Python 2.3, введён алгоритм C3 Linearization, разработанный для Dylanstructure. Это детерминированный и предсказуемый алгоритм.

class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass

# MRO3 (C3) порядок: D -> B -> C -> A
# Каждый класс посещается ровно один раз
print(D.__mro__)
# (<class D>, <class B>, <class C>, <class A>, <class object>)

Ключевые различия

1. Алгоритм вычисления

  • MRO2: DFS с проблемой дублирования
  • MRO3: C3 Linearization с гарантией монотонности

2. Свойства C3

class O: pass
class A(O): pass
class B(O): pass
class C(A, B): pass

# C3 гарантирует:
# 1. Каждый класс встречается ровно один раз
# 2. Порядок родителей сохраняется
# 3. Если X наследует Y, то X идет раньше Y в MRO

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

3. Линеаризация через слияние

C3 использует алгоритм слияния списков:

# Пример вычисления MRO для класса D(B, C):
# L[D] = D + merge(
#   L[B],
#   L[C],
#   [B, C]
# )

class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass

# L[B] = [B, A, O]
# L[C] = [C, A, O]
# L[D] = [D] + merge([B, A, O], [C, A, O], [B, C])
#      = [D, B] + merge([A, O], [C, A, O], [C])
#      = [D, B, C] + merge([A, O], [A, O])
#      = [D, B, C, A, O]

Практические различия

Проблема, которую решил MRO3:

# MRO2 вызывал ошибку TypeError для некоторых конфигураций
class A: pass
class B(A): pass
class C(B): pass
class D(A, C): pass  # MRO2: TypeError (нарушение монотонности)

# MRO3 (C3) решает это корректно:
# D.__mro__ = (D, A, C, B, object) - соответствует логике

Примеси (Mixins) с MRO3:

class Logger:
    def log(self, msg):
        print(f"[LOG] {msg}")

class Reader:
    def read(self):
        self.log("Reading...")
        return "data"

class FileReader(Reader, Logger):
    pass

fr = FileReader()
fr.read()  # Вызовет log() из Logger благодаря правильному MRO
# [LOG] Reading...

print(FileReader.__mro__)
# (FileReader, Reader, Logger, object)

super() и MRO3

MRO3 особенно важен при использовании super(), который следует порядку MRO:

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

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
# Именно благодаря MRO3 super() вызывает методы в правильном порядке

Выводы

Переход на MRO3 (C3 Linearization) в Python 2.3:

  • ✅ Устранил дублирование классов в цепочке наследования
  • ✅ Гарантировал монотонность и предсказуемость
  • ✅ Позволил использовать сложные множественные наследования безопасно
  • ✅ Сделал super() корректным инструментом для кооперативного наследования
  • ✅ Стал фундаментом современных паттернов (Mixins, Diamond Problem решение)

MRO3 — это один из ключевых принципов, обеспечивающих стабильность и предсказуемость Python при работе со сложными иерархиями классов.