super()如何处理多重继承?例如,给定:
class First(object):
def __init__(self):
print "first"
class Second(object):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
Third的哪个父方法执行super()。__init__ refer to?我可以选择哪些运行吗?
我知道这与方法解析顺序(MRO)有关。
class First(object):
def __init__(self, a):
print "first", a
super(First, self).__init__(20)
class Second(object):
def __init__(self, a):
print "second", a
super(Second, self).__init__()
class Third(First, Second):
def __init__(self):
super(Third, self).__init__(10)
print "that's it"
t = Third()
输出是
first 10
second 20
that's it
调用Third()定位在Third中定义的init。在这个例程中调用super调用First中定义的init。MRO =(一、二)。
现在在First中定义的init中调用super将继续搜索MRO并找到Second中定义的init,并且任何对super的调用都将命中默认对象init。我希望这个例子能够阐明这个概念。
如果你不在第一分局给管理员打电话。链条停止,您将得到以下输出。
first 10
that's it
在python 3.5+中,继承看起来是可预测的,对我来说非常好。
请看下面的代码:
class Base(object):
def foo(self):
print(" Base(): entering")
print(" Base(): exiting")
class First(Base):
def foo(self):
print(" First(): entering Will call Second now")
super().foo()
print(" First(): exiting")
class Second(Base):
def foo(self):
print(" Second(): entering")
super().foo()
print(" Second(): exiting")
class Third(First, Second):
def foo(self):
print(" Third(): entering")
super().foo()
print(" Third(): exiting")
class Fourth(Third):
def foo(self):
print("Fourth(): entering")
super().foo()
print("Fourth(): exiting")
Fourth().foo()
print(Fourth.__mro__)
输出:
Fourth(): entering
Third(): entering
First(): entering Will call Second now
Second(): entering
Base(): entering
Base(): exiting
Second(): exiting
First(): exiting
Third(): exiting
Fourth(): exiting
(<class '__main__.Fourth'>, <class '__main__.Third'>, <class '__main__.First'>, <class '__main__.Second'>, <class '__main__.Base'>, <class 'object'>)
正如你所看到的,它对每个继承链调用foo一次,其顺序与继承链的顺序相同。你可以通过调用.mro来获得订单:
Fourth -> Third -> First -> Second -> Base ->对象
考虑子AB,父A和B在它们的构造函数中有关键字参数。
A B
\ /
AB
要初始化AB,需要显式调用父类构造函数,而不是使用super()。
例子:
class A():
def __init__(self, a="a"):
self.a = a
print(f"a={a}")
def A_method(self):
print(f"A_method: {self.a}")
class B():
def __init__(self, b="b"):
self.b = b
print(f"b={b}")
def B_method(self):
print(f"B_method: {self.b}")
def magical_AB_method(self):
print(f"magical_AB_method: {self.a}, {self.b}")
class AB(A,B):
def __init__(self, a="A", b="B"):
# super().__init__(a=a, b=b) # fails!
A.__init__(self, a=a)
B.__init__(self, b=b)
self.A_method()
self.B_method()
self.magical_AB_method()
A()
>>> a=a
B()
>>> b=b
AB()
>>> a=A
>>> b=B
>>> A_method: A
>>> B_method: B
为了演示两个父类被组合到子类中,请考虑在类B中定义的magical_AB_method。当从B的实例调用时,该方法失败,因为它不能访问A中的成员变量。然而,当从子类AB的实例调用时,该方法工作,因为它从A继承了所需的成员变量。
B().magical_AB_method()
>>> AttributeError: 'B' object has no attribute 'a'
AB().magical_AB_method()
>>> magical_AB_method: A, B
你的代码和其他答案都是错误的。它们缺少前两个类中的super()调用,这是合作子类化工作所必需的。更好的是:
class First(object):
def __init__(self):
super(First, self).__init__()
print("first")
class Second(object):
def __init__(self):
super(Second, self).__init__()
print("second")
class Third(First, Second):
def __init__(self):
super(Third, self).__init__()
print("third")
输出:
>>> Third()
second
first
third
super()调用在每一步都在MRO中查找下一个方法,这就是为什么First和Second也必须拥有它,否则执行将在Second.__init__()结束时停止。
如果在First和Second中没有super()调用,输出就会丢失Second:
>>> Third()
first
third