简体   繁体   English

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

[英]python multiple inheritance, calling base class function

I was just trying something with multiple inheritance in python.我只是在尝试在 python 中使用多重继承。 I come up with this我想出了这个

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'

and it gives the following output它给出了以下输出

Child foo is called
ParentOne foo is called
ParentTwo foo is called

I am getting confused as to how calling of super(ParentOne, self).foo() is evaluated in this case.我对在这种情况下如何评估super(ParentOne, self).foo()调用感到困惑。 As per my understanding ParentOne class does not have any idea of the methods and attributes of ParentTwo class.根据我的理解, ParentOne类对ParentOne类的方法和属性ParentTwo How does super works in case of multiple inheritance多重继承时super如何工作

Python constructs a method resolution order (MRO) when it builds a class. Python 在构建类时会构造方法解析顺序 (MRO)。 The MRO is always linear. MRO始终是线性的。 If python cannot create a linear MRO, then a ValueError will be raised.如果 python 无法创建线性 MRO,则会引发ValueError In this case, your MRO probably looks like:在这种情况下,您的 MRO 可能看起来像:

Child -> ParentOne -> ParentTwo -> object

Now when python see's a super(cls, self) , it basically looks at self and figures out the MRO.现在,当 python see 是super(cls, self) ,它基本上会查看self并找出 MRO。 It then uses cls to determine where we are currently at in the MRO and finally it returns an object which delegates to the next class in the MRO.然后它使用cls来确定我们当前在 MRO 中的位置,最后它返回一个对象,该对象委托给 MRO 中的下一个类。 So, in this case, a super(Child, self) call would return an object that delegates to ParentOne .因此,在这种情况下, super(Child, self)调用将返回一个委托给ParentOne的对象。 A super(ParentOne, self) class would return an object that delegates to ParentTwo . super(ParentOne, self)类将返回一个委托给ParentTwo的对象。 Finally a super(ParentTwo, self) call would delegate to object .最后一个super(ParentTwo, self)调用将委托给object In other words, you can think of super as a fancier version of the following code:换句话说,您可以将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`

Note that since super(ParentTwo, self) returns a "Delegate" to object , we can see why you're getting an AttributeError when you try super(ParentTwo, self).foo() -- Specifically the reason is because object has no foo method.请注意,由于super(ParentTwo, self)object返回一个“Delegate”,我们可以看到为什么当您尝试super(ParentTwo, self).foo()时会收到AttributeError -- 具体原因是因为object没有foo方法。

You may understand Child(ParentOne, ParentTwo) as two separate inheritances within a chain: Child(ParentOne(ParentTwo)) .您可以将Child(ParentOne, ParentTwo)理解为链中的两个独立继承: Child(ParentOne(ParentTwo)) Actually, ParentOne doesn't inherit ParentTwo , they are two separate classes, but the method super works like there's a chain of inheritances (in case of multiple inheritance only).实际上, ParentOne不继承ParentTwo ,它们是两个独立的类,但是super方法的工作原理就像有一个继承链(仅在多重继承的情况下)。 I like this example to understand better what's going on (for Python 3.x):我喜欢这个例子来更好地理解发生了什么(对于 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()

It also considers a case if two parents inherit one base class.它还考虑了两个父级继承一个基类的情况。 The script above prints:上面的脚本打印:

P
B
A
C
P
B
A
P
B
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")

Given an instance:给定一个实例:

y = Y()

To call base class function:调用基类函数:

super(Y,y).run()
super(X1,y).run()
super(X2,y).run()
y.run()

Output输出

x1
x2
x3
y

Similarity,相似,

super(Y, y).run()
for cls in y.__class__.__bases__:
    if(cls != X3):
        super(cls,y).run()
y.run()

Output输出

x1
x2
x3
y

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM