python3 - 多重继承中super()的行为

9 投票
2 回答
3122 浏览
提问于 2025-04-18 09:26

我知道关于super()和多重继承的内容在这里已经讨论过了。但我没有找到针对我在python3中具体问题的解决方案。

假设我们有:

#! /usr/bin/env python3

class A(object):
    def __init__(self):
        super().__init__()

    def foo(self):
        print("The")

class B(object):
    def __init__(self):
        super().__init__()

    def foo(self):
        print("world")

class C(B):
    def __init__(self):
        super().__init__()

    def foo(self):
        super().foo()
        print("is")

class D(A,C):
    def __init__(self):
        super().__init__()

    def foo(self):
        super().foo()
        print("nice")

d = D()

d.foo()

这样会得到:

The
nice

另一方面,如果我把D()中的继承顺序改成:

class D(C,A):
    def __init__(self):
        super().__init__()

    def foo(self):
        super().foo()
        print("nice")

那么它会给我

world
is
nice

然而,我只想要得到期望的输出:

The
world
is
nice

使用:

class D(C,A):
    def __init__(self):
        super().__init__()

    def foo(self):
        A.foo(self)
        C.foo(self)
        print("nice")

我觉得这样做不太优雅。

所以我的问题是:在python3中,是否可以使用super()来调用两个父类的super方法,而不仅仅是第一个?

2 个回答

2

也许这会对你有帮助

 class A(object):
    def __init__(self):
        super().__init__()

    def foo(self):
        print("The")
        if hasattr(super(), 'foo'):
            super().foo()

class B(object):
    def __init__(self):
        super().__init__()

    def foo(self):
        print("world")

class C(B):
    def __init__(self):
        super().__init__()

    def foo(self):
        super().foo()
        print("is")

class D(A,C):
    def __init__(self):
        super().__init__()

    def foo(self):
        super().foo()
        print("nice")

d = D()

d.foo()

输出结果:

The
world
is
nice
4

很遗憾,如果不知道 D 的方法解析顺序(MRO),就无法在 D 中调用 super() 来同时访问两个父类。

不过,MRO 是一个很重要的概念。在第二种情况下,

class D(C,A):
    ...

这个 (MRO) 是

>>> D.mro()
[<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

正如 Pieters 先生所说,调用 super() 会让你进入 MRO 中的下一个类。如果你希望打印的顺序是 ABC,然后是 D,那么只需在每个 foo() 的定义中先写 super().foo(),再写 print(...)。唯一的例外是,不要在类 A 中写 super().foo(),因为 foo()object 中并没有定义。

解决方案

#! /usr/bin/env python3

class A(object):
    def __init__(self):
        super().__init__()

    def foo(self):
        print("The")

class B(object):
    def __init__(self):
        super().__init__()

    def foo(self):
        super().foo()      # Inserted
        print("world")

class C(B):
    def __init__(self):
        super().__init__()

    def foo(self):
        super().foo()
        print("is")

class D(C,A):              # Correct ordering
    def __init__(self):
        super().__init__()

    def foo(self):
        super().foo()
        print("nice")

d = D()

d.foo()

替代解决方案

在第一种情况下,D(A,C) 的 MRO 也包含所有类,因此只要正确安排 super()print(...) 的顺序,就可以让它正常工作:

class A(object):
    def foo(self):
        print("The")
        super().foo()

class B(object):
    def foo(self):
        print("world")

class C(B):
    def foo(self):
        super().foo()
        print("is")

class D(A,C):
    def foo(self):
        super().foo()
        print("nice")

D().foo()

进一步阅读

要理解继承顺序(例如 class D(C,A)class D(A,C))和 MRO,可以查看 https://www.python.org/download/releases/2.3/mro/。文中详细描述了 C3 方法解析顺序,并且有清晰的 ASCII 类层次结构图,标注了 MRO。

撰写回答