Что такое MRO
MRO – method resolution order, порядок разрешения методов. Алгоритм, по которому следует искать метод в случае, если у класса два и более родителей.
В классических классах поиск при наследовании по ссылкам на имена осуществляется в следующем порядке:
- Сначала экземпляр
- Затем его класс
- Далее все суперклассы его класса с обходом сначала с глубину, а затем слева направо
Используется первое обнаруженное вхождение. Такой порядок называется DFLR (Обход в глубину и слева направо).
При наследовании классов нового стиля применяется правило MRO (порядок разрешения методов), т.е. линеаризованный обход дерева классов, причем вложенный элемент наследования становится доступным в атрибуте __mro__ данного класса. Такой алгоритм называется C3-линеаризация. Наследование по правилу MRO осуществляется приблизительно в следующем порядке.
- Перечисление всех классов, наследуемых экземпляром, по правилу поиска DFLR для классических классов, причем класс включается в результат поиска столько раз, сколько он встречается при обходе.
- Просмотр в полученном списке дубликатов классов, из которых удаляются все, кроме последнего (крайнего справа) дубликата в списке.
Упорядочение по правилу MRO применяется при наследовании и вызове встроенной функции super(), которая всегда вызывает следующий по правилу MRO класс (относительно точки вызова).
Пример наследования в неромбовидных иерархических деревьях:
class D: attr = 3 # D:3 E:2
class B(D) pass # | |
class E: attr = 2 # B C:1
class C(E): attr = 1 # / /
class A(B, C): pass # A
X = A() # |
print(X.attr) # X
# DFLR = [X, A, B, D, C, E]
# MRO = [X, A, B, D, C, E, object]
# И в версии 3.х и в версии 2.х (всегда) выводит строку "3"
Пример наследования в ромбовидных иерархических деревьях:
class D: attr = 3 # D:3 D:3
class B(D) pass # | |
class C(D): attr = 1 # B C:1
class A(B, C): pass # / /
X = A() # A
print(X.attr) # |
# X
# DFLR = [X, A, B, D, C, D]
# MRO = [X, A, B, C, D, object] (сохраняет только последний дубликат D)
# Выводит строку "1" в версии 3.х, строку "3" в версии 2.х ("1" если D(object))
Oct. 10, 2023, Источник
- Это порядок разрешения методов (Порядок, в котором Python ищет методы в иерархии классов)
- Можно узнать порядок через функцию mro() или через магический метод mro
- Порядок разрешения методов основан на алгоритме C3 линеаризации, этот алгоритм преобразовывает граф в список, по порядку поиска.
- Сначала идут родители, потом дедушки/бабушки, потом прабабушки/прадедушки
Цель MRO: убедиться, что правильный метод вызывается, когда в иерархии классов определено несколько методов с одним и тем же именем.
Oct. 10, 2023, Источник