🖥 Что такое MRO ?



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



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



1. Сначала экземпляр

2. Затем его класс

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

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



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



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

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

Упорядочение по правилу MRO применяется при наследовании и вызове встроенной функции super(), которая всегда вызывает следующий по правилу MRO класс (относительно точки вызова).



Пример наследования в неромбовидных иерархаических деревьях:



class 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 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))



@python_job_interview