MRO и C3
Порядок поиска методов в множественном наследовании.
MRO и алгоритм C3
MRO (Method Resolution Order) — порядок, в котором Python ищет атрибуты и методы при множественном наследовании. Когда ты пишешь obj.method(), интерпретатор перебирает классы по списку cls.__mro__ слева направо и берёт первый, где метод найден. Алгоритм построения этого списка — C3-линеаризация — гарантирует три свойства: дочерний идёт раньше родителей, порядок баз сохраняется, а каждый класс встречается ровно один раз.
Как читается
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.__mro__)
(D, B, C, A, object)
C3 идёт по слиянию (merge) линеаризаций родителей: L[D] = D + merge(L[B], L[C], [B,C]). На каждом шаге выбирается «голова» того списка, которой нет в «хвостах» других. Если корректного порядка не существует (например, class X(B, A) где A базовый для B), Python поднимает TypeError: Cannot create a consistent method resolution order.
Пример: алмаз с super()
class A:
def hi(self): print("A")
class B(A):
def hi(self): print("B"); super().hi()
class C(A):
def hi(self): print("C"); super().hi()
class D(B, C):
def hi(self): print("D"); super().hi()
D().hi()
D, B, C, A — каждый класс выполнен ровно раз благодаря MRO
Когда полезно знать / подводные камни
👍 Mixin-архитектура (Django views, DRF), кооперативные super()-цепочки, понимание, почему super() без аргументов «угадывает» правильный класс.
👎 Если в иерархии есть классы, не вызывающие super(), цепочка обрывается. Любое изменение порядка баз в class D(C, B) меняет MRO и поведение программы — это «дальнодействующая» правка. При сложных деревьях смотри Klass.__mro__ или Klass.mro() в дебаге.