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)有关。
在这种情况下,你试图继承的每个类都有自己的init位置参数,只需调用每个类自己的init方法,如果试图继承多个对象,则不要使用super。
class A():
def __init__(self, x):
self.x = x
class B():
def __init__(self, y, z):
self.y = y
self.z = z
class C(A, B):
def __init__(self, x, y, z):
A.__init__(self, x)
B.__init__(self, y, z)
>>> c = C(1,2,3)
>>>c.x, c.y, c.z
(1, 2, 3)
在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
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多重继承应该使用菱形模型,并且函数签名不应该在模型中更改。
A
/ \
B C
\ /
D
示例代码片段为;-
class A:
def __init__(self, name=None):
# this is the head of the diamond, no need to call super() here
self.name = name
class B(A):
def __init__(self, param1='hello', **kwargs):
super().__init__(**kwargs)
self.param1 = param1
class C(A):
def __init__(self, param2='bye', **kwargs):
super().__init__(**kwargs)
self.param2 = param2
class D(B, C):
def __init__(self, works='fine', **kwargs):
super().__init__(**kwargs)
print(f"{works=}, {self.param1=}, {self.param2=}, {self.name=}")
d = D(name='Testing')
这里类A是对象