Почему __init__ пропускается при выполнении Base .__ init __ (self) в множественном наследовании вместо super () .__ init __ ()? - PullRequest
0 голосов
/ 07 октября 2018

Почему точно печатается

A.__init__()
B.__init__()
D.__init__()

с помощью следующего кода?В частности:

  1. Почему C.__init__() не напечатано?

  2. Почему печатается C.__init__(), если я поставлюsuper().__init__() вместо A.__init__(self)?

#!/usr/bin/env python3

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

D()

1 Ответ

0 голосов
/ 07 октября 2018

tl; dr: потому что B.__init__ - это то, что должно было вызвать C.__init__ через super(B, self).__init__(), и вы обошли этот вызов.


Почему C .__ init __ ()не напечатано?

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

Если бы вы заменили все "супер-подобные" вызовы на super().__init__() (так как вы пометили его как Python 3), вывы увидите вывод вида:

A.__init__()
C.__init__()
B.__init__()
D.__init__()

Фактически, вы увидите этот вывод, если вы просто изменили просто «супер-подобный» вызов B на:

super(B, self).__init__()
super().__init__()

Так почему А не вызвал С в вашем случае?

Было бы излишним копировать хорошо изложенные ответы в другом месте на сайте о MRO.

ПочемуC .__ init __ () печатается, если я ставлю super () .__ init __ () вместо A .__ init __ (self)?

Поскольку супер-аргумент без аргументов идет слева направо , поэтому сначала просматривается B, а затем внутри B вы используете явную ссылку на класс (A.__init__(self)).И при этом вы теряете весь (самый *) контекст, который D также имел в качестве суперкласса C.

super() - это то, что помогает вам ориентироваться в MRO, и привело бы вас к C.__init__(), если бы вы позволили.Но в B вы просто вызываете метод класса A.

* Как вы заметили, C.__init__() никогда не вызывается.Тем не менее, C по-прежнему отображается в D.__bases__:

(<class '__main__.B'>, <class '__main__.C'>)

в D.__mro__:

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

и isinstance(D(), C) is True.

Короче говоря,Python знает , что C является суперклассом D, но вы дали C.__init__ и завершили свою реализацию B.__init__.

...