我只是尝试在python中使用多重继承。我想出了这个
class ParentOne:
def foo(self):
print("ParentOne foo is called")
class ParentTwo:
def foo(self):
print("ParentTwo foo is called")
class Child(ParentOne, ParentTwo):
# how is this working
def call_parent_two_foo(self):
super(ParentOne, self).foo()
# This does not work
def call_parent_foo(self):
super(ParentTwo, self).foo()
def call_super_foo(self):
super(Child, self).foo()
def foo(self):
print("Child foo is called")
if __name__ == "__main__":
child = Child()
child.foo()
child.call_super_foo()
child.call_parent_two_foo()
# child.call_parent_foo() #This gives the below error
# super(ParentTwo, self).foo()
# AttributeError: 'super' object has no attribute 'foo'
并提供以下输出
Child foo is called
ParentOne foo is called
ParentTwo foo is called
我对在这种情况下如何评估super(ParentOne, self).foo()
的调用感到困惑。根据我的理解,ParentOne
类对ParentTwo
类的方法和属性一无所知。在多重继承的情况下,super如何工作
答案 0 :(得分:4)
Python在构建类时构造方法解析顺序(MRO)。 MRO 总是线性。如果python无法创建线性MRO,那么将引发ValueError
。在这种情况下,您的MRO可能看起来像:
Child -> ParentOne -> ParentTwo -> object
现在当python看到super(cls, self)
时,它基本上会看self
并找出MRO。然后使用cls
确定我们当前在MRO中的位置,最后它返回一个委托给MRO中 next 类的对象。因此,在这种情况下,super(Child, self)
调用将返回委托给ParentOne
的对象。 super(ParentOne, self)
类将返回委托给ParentTwo
的对象。最后,super(ParentTwo, self)
来电将委托给object
。换句话说,您可以将super
视为以下代码的更高版本:
def kinda_super(cls, self):
mro = inspect.getmro(type(self))
idx = mro.index(cls)
return Delegate(mro[idx + 1]) # for a suitably defined `Delegate`
请注意,由于super(ParentTwo, self)
会向object
返回“代理人”,因此我们可以看到您在尝试AttributeError
时获得super(ParentTwo, self).foo()
的原因 - 特别是原因是因为object
没有foo
方法。
答案 1 :(得分:0)
您可以将Child(ParentOne, ParentTwo)
理解为链中的两个单独的继承:Child(ParentOne(ParentTwo))
。实际上,ParentOne
并没有继承ParentTwo
,它们是两个独立的类,但方法super
就像那里的继承链一样(仅在多重继承的情况下) )。我喜欢这个例子来更好地理解正在发生的事情(对于Python 3.x):
class P:
def m(self):
print("P")
class A(P):
def m(self):
super().m() # -> B, if we inherit like C(A, B)
print("A")
class B(P):
def m(self):
super().m() # -> P, if we inherit like C(A, B)
print("B")
class C(A, B):
def m(self):
super().m() # -> A
print("C")
A.m(self)
B.m(self)
c = C()
c.m()
如果两个父母继承一个基类,它也会考虑一个案例。上面的脚本打印:
P
B
A
C
P
B
A
P
B
答案 2 :(得分:0)
class X1:
def run(self):
print("x1")
class X2:
def run(self):
print("x2")
class X3:
def run(self):
print("x3")
class X2:
def run(self):
print("x2")
class Y(X1, X2, X3):
def run(self):
print("y")
给出一个实例:
y = Y()
调用基类函数:
super(Y,y).run()
super(X1,y).run()
super(X2,y).run()
y.run()
输出
x1
x2
x3
y
相似性
super(Y, y).run()
for cls in y.__class__.__bases__:
if(cls != X3):
super(cls,y).run()
y.run()
输出
x1
x2
x3
y