Почему вызов 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__
, а затем другие сообщения печатаются по пути вниз по дереву наследования.)