Ответ
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'>) Ответ 18+ 🔞
Ах ты ж ёпта, ну и тема у нас сегодня! MRO, блядь! Это ж та самая штука, которая решает, какого хуя твой метод будет найден, когда у тебя куча классов друг на друга наворочена. Как в той семье, где все друг другу родственники, и непонятно, кого слушать. Так вот, в Питоне это слушание и называется MRO.
Вот смотри, раньше, в старые добрые времена Python 2, была полная ёбаная неразбериха. Как два разных государства: классические классы и новые.
Классические классы (Old-style classes)
Это как дедовский метод, наследуются они не от object, а просто так, с потолка. И алгоритм у них был, блядь, примитивный до безобразия: «сначала в глубину, потом слева направо». И вот эта простота, сука, приводила к пиздецу в ромбовидном наследовании.
# Запомни, это только для 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")
class D(B, C):
pass
d = D()
d.who_am_i() # Вывод: I am A
Вот видишь, ебаный насос! Порядок поиска был: D -> B -> A. И всё! Нашёл метод в A и успокоился, как будто класса C с его переопределённым методом не существует в природе! Пиздец, да? Класс C сидит и думает: «Я тут, блядь, старался, переписывал, а меня в упор не видят!». Вот такие были времена, в рот меня чих-пых.
Новые классы (New-style classes)
А потом пришёл светлый разум. Все классы стали наследоваться от object, явно или неявно. И для них придумали умный алгоритм — C3-линеаризацию. Он, сука, гарантирует, что дочерние классы всегда идут перед родительскими. Проблема ромбовидного наследования накрылась медным тазом.
# А вот это уже работает везде, и это правильно
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")
class D(B, C):
pass
d = D()
d.who_am_i() # Вывод: I am C
Вот теперь порядок поиска (MRO) стал адекватным: D -> B -> C -> A -> object. Сначала проверил D, потом B, не нашёл, пошёл в C — о, ёба, нашёл! И вызвал его. Всё логично, всё справедливо. Красота, блядь.
И самое главное — ты можешь посмотреть эту цепочку наследования, как на параде. Есть два способа, оба рабочие:
print(D.__mro__)
# Или так:
print(D.mro())
# Выдаст тебе кортеж или список: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
Вот и вся магия, ёпта. Главное запомни: в Python 3 все классы — новые, и алгоритм C3 — наш царь и бог. А старые классические классы — это как история про то, как Герасим Муму утопил: вроде и жалко, но правильно сделал, что от них избавились.