2016-09-10 2 views
-1

я следующий код:Как работает Python 3 super() в этой конкретной ситуации множественного наследования?

class A: 
    def __init__(self): 
     print("A.__init__") 

class B(A): 
    def __init__(self): 
     print("B.__init__") 
     super().__init__() 

class C(A): 
    def __init__(self): 
     print("C.__init__") 
     super().__init__() 


class D(B,C): 
    def __init__(self): 
     print("D.__init__") 
     super().__init__() 

Когда я создаю экземпляр объекта из класса D,

d = D() 

я получил:

>>> d = D() 
D.__init__ 
B.__init__ 
C.__init__ 
A.__init__ 

Почему __init__() только получил колл класса А-х один раз и в самом конце? Обратите внимание на класс B и класс C, называемый классом A __init__(), поэтому я ожидал, что класс A __init__() должен вызываться дважды.

Я прочитал как документацию Python 3, так и блог г-на Хеттингера, но не понял, в чем заключается механизм. Итак, как super() определяет, что его нужно выполнить только один раз? Благодарю.

+0

Может вниз избиратель, пожалуйста, объясните немного, почему вы проголосовали вниз мой вопрос ?? Я честно не понимаю. Thx –

+0

Каждый метод вызывает 'super() .__ init __()', ** not ** '.. Init. __()'. Почему вы думаете, что «A .__ init__» - это то же самое в этих случаях? –

+0

'super()' смотрит на класс MRO (порядок разрешения метода). Для множественного наследования (график наследования алмазов) MRO все еще будет * linear *, чтобы избежать вызова 'A .__ init __()' более одного раза. Посмотрите на 'D .__ mro__', чтобы увидеть фактический MRO, определенный во время выполнения, вы увидите, что это' [D, B, C, A] '. Прочитайте [Документацию MIP Python] (https://www.python.org/download/releases/2.3/mro/), чтобы узнать, почему и как. –

ответ

0

У Python есть механизм под названием Order Resolution Method (MRO) для поиска правильных методов в иерархиях классов. Есть два правила в MRO:

1- отдел-первых слева направо поиск

2- последнее появление класса рассматривается только

Теперь вернемся к вашему примеру:

I. Поиск начинается с D, добавляя его в список MRO [D].

II. Класс D наследуется от B и C. B является самым левым родителем, а затем набирает C. Таким образом, список MRO становится [D, B, C].

III. Затем поиск продолжается до более глубокого уровня с родителем B и A добавляется в список. Теперь мы имеем [D, B, C, A]. Поиск продолжается родителями C с снова A. Поскольку A уже в списке, ничего не меняется.

IV. Поиск идет на более глубокий уровень (родители А), и поскольку у A нет явного родителя, поиск заканчивается на этом этапе.

Таким образом, окончательный список - [D, B, C, A].

супер() метод использует этот список, чтобы делать свою работу, и вот почему А называется в конце

+0

Спасибо за ваш ответ. Я немного затрудняюсь понять ваш номер 2 (рассматривается только последнее вхождение класса). На что вы ссылаетесь, когда говорите «возникновение»? Вызывает ли его метод подсчет как событие? В моем примере, могу ли я сказать, что класс А произошел дважды? Большое спасибо. –

+0

Всякий раз, когда процесс поиска посещает класс, его необходимо добавить в список, но если класс уже добавлен, он удаляется и затем добавляется в конец списка.Таким образом, гарантируется, что каждый класс добавляется в список MRO только один раз и последний раз, когда класс появляется в процессе поиска. Надеюсь, что это поможет @JinghuiNiu –

+0

@ Farzan Hajian У меня есть продолжение здесь, что, если у меня есть ситуация, когда мне нужно вызывать __init __() класса A дважды в B и C? Будет ли MRO механически игнорировать мою просьбу и только один раз ссылаться независимо от ситуации? Есть ли способ преодолеть это? –

Смежные вопросы