← Назад к вопросам
Какое изменение произошло при переходе из 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 при работе со сложными иерархиями классов.