Что такое MRO

MRO – method resolution order, порядок разрешения методов. Алгоритм, по которому следует искать метод в случае, если у класса два и более родителей.

В классических классах поиск при наследовании по ссылкам на имена осуществляется в следующем порядке:

  1. Сначала экземпляр
  2. Затем его класс
  3. Далее все суперклассы его класса с обходом сначала с глубину, а затем слева направо

Используется первое обнаруженное вхождение. Такой порядок называется DFLR (Обход в глубину и слева направо).

При наследовании классов нового стиля применяется правило MRO (порядок разрешения методов), т.е. линеаризованный обход дерева классов, причем вложенный элемент наследования становится доступным в атрибуте __mro__ данного класса. Такой алгоритм называется C3-линеаризация. Наследование по правилу MRO осуществляется приблизительно в следующем порядке.

  1. Перечисление всех классов, наследуемых экземпляром, по правилу поиска DFLR для классических классов, причем класс включается в результат поиска столько раз, сколько он встречается при обходе.
  2. Просмотр в полученном списке дубликатов классов, из которых удаляются все, кроме последнего (крайнего справа) дубликата в списке.

Упорядочение по правилу 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, Источник