Ответ Джейкоба показывает, как понять проблему, в то время как батбрат показывает детали, и г-н идет прямо к делу.
Одна вещь, которую они не охватывают (по крайней мере, не ясность) из вашего вопроса, это:
Однако, если вы закомментируете вызов super в функции инициализации B, не вызывается ни функция инициализации A, ни C.
Чтобы понять это, измените код Джейкоба на печать стека в инициализации А, как показано ниже:
import traceback
class A(object):
def __init__(self):
print "A init"
print self.__class__.__mro__
traceback.print_stack()
class B(A):
def __init__(self):
print "B init"
print self.__class__.__mro__
super(B, self).__init__()
class C(A):
def __init__(self):
print "C init"
print self.__class__.__mro__
super(C, self).__init__()
class D(B, C):
def __init__(self):
print "D init"
print self.__class__.__mro__
super(D, self).__init__()
x = D()
Немного удивительно видеть, что строка B
super(B, self).__init__()
фактически вызывает C.__init__()
, поскольку C
не является базовым классом B
.
D init
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
B init
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
C init
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
A init
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
File "/tmp/jacobs.py", line 31, in <module>
x = D()
File "/tmp/jacobs.py", line 29, in __init__
super(D, self).__init__()
File "/tmp/jacobs.py", line 17, in __init__
super(B, self).__init__()
File "/tmp/jacobs.py", line 23, in __init__
super(C, self).__init__()
File "/tmp/jacobs.py", line 11, in __init__
traceback.print_stack()
Это происходит потому, что super (B, self)
не является ', вызывающим версию базового класса B для __init__
'. Вместо этого вызывает __init__
в первом классе справа от B
, который присутствует в self
* __mro__
, и имеет такой атрибут .
Итак, если вы закомментируете вызов super в функции инициализации B , стек методов остановится на B.__init__
и никогда не достигнет C
или A
.
Подведем итог:
- Независимо от того, какой класс ссылается на него,
self
всегда является ссылкой на экземпляр, и его __mro__
и __class__
остаются постоянными
- super () находит метод, ищущий классы, которые находятся справа от текущего в
__mro__
. Поскольку __mro__
остается постоянным, происходит поиск в виде списка, а не дерева или графика.
В этом последнем пункте обратите внимание, что полное имя алгоритма MRO - C3 линеаризация суперкласса . То есть, она сплющивает эту структуру в список. Когда происходят разные вызовы super()
, они эффективно повторяют этот список.