python多重继承,调用基类函数

时间:2016-12-28 06:14:43

标签: python python-2.7 python-3.x inheritance

我只是尝试在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如何工作

3 个答案:

答案 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