метод разрешение порядок ТОиР

Почему после поиска B он не углубляется в поиск Y ИЛИ z, а переходит к поиску A?

Y является родителем A, если сначала следует искать A, но Y является родителем B, поэтому он должен сначала искать Y, почему это не вызывает ошибку MRO?

Может кто-нибудь объяснить, как работает этот поиск?

class X(object):pass
class Y(object): pass
class Z(object): pass
class A(X,Y): pass
class B(Y,Z):pass
class M(B,A,Z):pass
print M.__mro__

дает

(<class '__main__.M'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.X'>, <class '__main__.Y'>, <class '__main__.Z'>, <type 'object'>)

введите здесь описание изображения


person Lisa    schedule 15.04.2019    source источник
comment
Это стандартная линеаризация C3.   -  person Matthias    schedule 15.04.2019


Ответы (1)


В вашем конкретном примере после поиска B мы не можем сразу рассмотреть Y, потому что это дочерний элемент A. Мы не можем рассматривать Z сразу, потому что M наследуется от A до наследования от Z.


Python использует порядок разрешения методов C3 подробности здесь .

Порядок разрешения C3 хорошо решает проблему наследования алмазов

В приведенном ниже примере у нас есть очень общий класс Object, который является суперклассом B и C. Мы хотим, чтобы реализации методов (скажем, __repr__ или что-то в этом роде) в Object рассматривались только в том случае, если ни B, ни C не имеют реализации.

         Object
         /   \
        B     C
         \   /
           A

Другими словами, каждый возможный родитель в транзитивном замыкании родительских классов A рассматривается, но классы упорядочены в соответствии с "самым последним" путем от базового класса к рассматриваемому классу.

Есть два пути к object:

A -> B -> Object
A -> C -> Object

«Последний» путь — A -> C -> Object, потому что A -> B -> Object будет раньше в левостороннем поиске в глубину.

Линеаризация C3 удовлетворяет двум ключевым инвариантам:

  • если X наследуется от Y, X проверяется перед Y.
  • если Z наследуется от U, а затем V в таком порядке, U проверяется перед V.

Действительно, C3 линеаризация гарантирует выполнение обоих этих свойств.

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

работает inherit.py

class E: pass      
class F: pass
class A(E, F): pass
class B(F, E): pass
class Z(A, B): pass

выдает следующую ошибку.

Traceback (most recent call last):
  File "inherit.py", line 5, in <module>
    class Z(A, B): pass
TypeError: Cannot create a consistent method resolution
order (MRO) for bases E, F
person Gregory Nisbet    schedule 15.04.2019
comment
Не могли бы вы объяснить пример, который я привожу? @Грегори Нисбет? по какой причине после проверки B он проверяет A вместо Y? Прочитав ваше объяснение, я понял: A наследуется от X и Y, поэтому мы должны проверять A, а не Y, не так ли? - person Lisa; 15.04.2019
comment
@ Лиза ... Да. Мы должны отложить проверку Y, потому что A также наследуется от Y. классы с несколькими путями наследования к ним проверяются как можно позже. - person Gregory Nisbet; 16.04.2019
comment
@Lisa Подумайте об этом так: M больше похож на A, потому что он наследуется от A напрямую, в отличие от Y, который наследуется только косвенно (через B и A), что означает, что мы хотели бы использовать определение метода из A в предпочтение к одному из Y. - person chepner; 16.04.2019
comment
@chepner Возможно, я неправильно истолковал ваш комментарий, но, похоже, он предполагает, что мы проходим иерархию наследования в ширину, чтобы искать реализации методов, а не так, как работает C3. - person Gregory Nisbet; 17.04.2019
comment
Я просто хотел объяснить, почему C3 ставит A перед Y. (Хотя, переходит ли C3 к BFS, если вы никогда явно не наследуете от одного из предков вашего родителя? Десять секунд размышлений не привели к контрпримеру :)) - person chepner; 17.04.2019
comment
@chepner ... C3 переходит в DFS, если мы находимся в дереве. Если A < B, C и B < D < E... то проверим A, B, D, E, C. При обозначении X < P1, P2 значение X наследуется от P1, а затем от P2. - person Gregory Nisbet; 17.04.2019
comment
Ах, этот ответ дает пример, когда C3 расходится с шириной, по причинам, которые мой комментарий не охватывает. - person chepner; 17.04.2019