Ответ
MRO (Method Resolution Order) определяет последовательность, в которой Python ищет метод в иерархии классов при множественном наследовании. В Python 2 существовало два разных подхода к MRO, зависящих от типа класса.
Важно: Поведение "классических классов" является устаревшим. В современном Python 3 все классы являются "новыми" и используют исключительно алгоритм C3.
1. Классические классы (Old-style classes)
Это классы, которые не наследуются от object. Они использовали простой алгоритм "сначала в глубину, затем слева направо" (depth-first, left-to-right). Этот подход мог приводить к проблемам при ромбовидном наследовании.
# Этот код корректно работает только в Python 2
class A:
def who_am_i(self): print("I am A")
class B(A):
pass
class C(A):
def who_am_i(self): print("I am C")
# Порядок наследования: B, C
class D(B, C):
pass
d = D()
d.who_am_i() # Вывод: I am A
Порядок поиска: D -> B -> A. Поиск доходит до A и останавливается, не проверяя класс C, хотя он ближе в иерархии.
2. Новые классы (New-style classes)
Это классы, которые явно или неявно наследуются от object. Для них используется более совершенный алгоритм C3-линеаризации. Он гарантирует, что дочерние классы всегда проверяются раньше родительских, решая проблему ромбовидного наследования.
# Этот код работает и в Python 2, и в Python 3
class A(object):
def who_am_i(self): print("I am A")
class B(A):
pass
class C(A):
def who_am_i(self): print("I am C")
# Порядок наследования: B, C
class D(B, C):
pass
d = D()
d.who_am_i() # Вывод: I am C
Порядок поиска (MRO): D -> B -> C -> A -> object. Поиск находит метод в C после проверки B и вызывает его.
Посмотреть MRO для класса можно с помощью атрибута __mro__ или метода .mro():
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)