Почему вызов super() в родительском классе __init__() меняет поведение подкласса __init__()?

Я пытался понять поведение super() в контексте множественного наследования. Я не понимаю, почему звонки super() в родительских классах в test2.py вызывают __init__() быть призванным для обоих родителей?

test1.py

#!/usr/bin/env python

class A(object):

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

class B(object):

    def __init__(self):
        self.B = "B"
        print self.B

class C(A, B):

    def __init__(self):
        self.C = "C"
        print self.C
        super(C, self).__init__()

if __name__ == '__main__':
    print "Without super() in parent __init__():"
    c = C()
    print c.__dict__
    print C.__mro__

производит:

$ ./test.py 
Without super() in parent __init__():
C
A
{'A': 'A', 'C': 'C'}
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)

test2.py

#!/usr/bin/env python

class A(object):

    def __init__(self):
        self.A = "A"
        print self.A
        super(A, self).__init__()

class B(object):

    def __init__(self):
        self.B = "B"
        print self.B
        super(B, self).__init__()

class C(A, B):

    def __init__(self):
        self.C = "C"
        print self.C
        super(C, self).__init__()

if __name__ == '__main__':
    print "With super() in parent __init__():"
    c = C()
    print c.__dict__
    print C.__mro__

производит:

$ ./test2.py 
With super() in parent __init__():
C
A
B
{'A': 'A', 'C': 'C', 'B': 'B'}
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)

1 ответ

Решение

Ваша ошибка в вашем комментарии:

super(C, self).__init__()  <-- call to object.__init__()

Это не призыв к object.__init__, Причина, по которой вы передаете и класс C, и экземпляр self в super так что он знает, что вызывать дальше, не только на основе суперклассов класса, но и на основе MRO экземпляра. По существу, super(C, self).__init__ значит "позвони __init__ класса после C в собственной MRO".

Это весь смысл super --- это позволяет кооперативное наследование, когда класс может просто вызвать super означать "передать контроль следующему классу в MRO", при этом не нужно знать во время определения класса, какой это класс.

Поэтому, когда вы звоните super(C, self).__init__, что вызывает A.__init__, потому что A следующий класс после C в MRO. Затем, когда звонит super(A, self).__init__, что вызывает B.__init__, потому что B является классом после A в MRO.

(Обратите внимание, что ваши сообщения печатаются в обратном порядке - B, A, C - потому что вы печатаете каждое сообщение после вызова метода суперкласса. Таким образом, первое сообщение не печатается до тех пор, пока его выполнение не достигнет B.__init__, а затем другие сообщения печатаются по пути вниз по дереву наследования.)

Другие вопросы по тегам