Вы не можете делать то, о чем просите в C.__init__
, так как super
не дает вам никакого контроля над тем, какие конкретные унаследованные методы вызываются, только в порядке, в котором они вызываются, и это полностью контролируетсяпорядок, в котором перечислены родительские классы.
Если вы используете super
, вам необходимо использовать его последовательно в всех классах.(Вот почему это называется кооперативное наследование.) Обратите внимание, это означает, что C
не может вводить какой-либо код между вызовами A.__init__
и B.__init__
.
__init__
особенно сложноправильно реализовать при использовании super
, потому что правило super
состоит в том, что вы должны ожидать, что будут переданы произвольные аргументы, но object.__init__()
не принимает никаких аргументов.Вам необходимо, чтобы каждый дополнительный аргумент «принадлежал» определенному корневому классу, который отвечает за его удаление из списка аргументов.
class A:
def __init__(self, foo, **kwargs):
# A "owns" foo; pass everything else on
super().__init__(**kwargs)
self.foo = foo
class B:
def __init__(self, bar, **kwargs):
# B "owns" bar; pass everything else on
super().__init__(**kwargs)
self.bar = bar
class C(A,B):
def __init__(self):
# Must pass arguments expected by A and B
super().__init__(foo=3, bar=9)
MRO для C
равно [A, B, object]
, поэтому дерево вызововвыглядит примерно так:
C.__init__
вызывается без аргументов super()
разрешается в A
, поэтому A.__init__
вызывается с foo=3
и bar=9
. - В
A.__init__
, super()
разрешается в B
, поэтому B.__init__
вызывается с bar=9
. - В
B.__init__
, super()
разрешается в object
, поэтому object.__init__
вызывается без аргументов (kwargs
является пустым) - Как только
object.__init__
возвращается, self.bar
устанавливается в bar
- Однажды
B.__init__
возвращается, self.foo
устанавливается на foo
- Как только
A.__init__
возвращается, C.__init__
заканчивает
ОК, первое предложение не совсем верно,Поскольку ни A
, ни B
, как написано в настоящее время, не используют super
, вы можете быть в состоянии предположить, что соответствующее использование super
просто вызовет одну родительскую функцию и немедленно вернется.
class A:
def __init__(self, foo):
self.foo = foo
class B:
def __init__(self, bar):
self.bar == bar
class C(A,B):
def __init__(self):
super(A, self).__init__(foo=3)
# Do some calculation
super(B, self).__init__(bar=9)
Я не совсем уверен, однако, что это не приводит к некоторым трудно предсказуемым ошибкам, которые могут проявляться с другими подклассами A
, B
и / или C
которые пытаются использовать super
правильно.