多重继承调用顺序

发布于 2024-12-25 13:35:57 字数 2136 浏览 2 评论 0原文

 A      B
| |   |   |
C D   E   F
| |   |   |
    G     H
      |
      I


user@ubuntu:~/Documents/Python/oop_python$ cat tt.py
class A:
    def call_me(self):
        print("A")

class C(A):
    def call_me(self):
        super().call_me()
        print("C")

class D(A):
    def call_me(self):
        super().call_me()
        print("D")

class B:
    def call_me(self):
        print("B")

class E(B):
    def call_me(self):
        super().call_me()
        print("E")

class F(B):
    def call_me(self):
        super().call_me()
        print("F")

class G(C, D, E):
    def call_me(self):
        super().call_me()
        print("G")

class H(F):
    def call_me(self):
        super().call_me()
        print("H")

class I(G, H):
    def call_me(self):
        super().call_me()
        print("I")


user@ubuntu:~/Documents/Python/oop_python$ python3.2 -i tt.py
>>> i = I()
>>> i.call_me()
A
D
C
G
I

问题>为什么BEF不打印?

//            updated based on comments from delnan

user@ubuntu:~/Documents/Python/oop_python$ cat tt.py
class BaseClass():
    def call_me(self):
        print("BaseClass")
    pass

class A(BaseClass):
    def call_me(self):
        super().call_me()
        print("A")

class C(A):
    def call_me(self):
        super().call_me()
        print("C")

class D(A):
    def call_me(self):
        super().call_me()
        print("D")

class B(BaseClass):
    def call_me(self):
        super().call_me()
        print("B")

class E(B):
    def call_me(self):
        super().call_me()
        print("E")

class F(B):
    def call_me(self):
        super().call_me()
        print("F")

class G(C, D, E):
    def call_me(self):
        super().call_me()
        print("G")

class H(F):
    def call_me(self):
        super().call_me()
        print("H")

class I(G, H):
    def call_me(self):
        super().call_me()
        print("I")

user@ubuntu:~/Documents/Python/oop_python$ python3.2 -i tt.py
>>> i = I()
>>> i.call_me()
BaseClass
B
F
H
E
A
D
C
G
I
 A      B
| |   |   |
C D   E   F
| |   |   |
    G     H
      |
      I


user@ubuntu:~/Documents/Python/oop_python$ cat tt.py
class A:
    def call_me(self):
        print("A")

class C(A):
    def call_me(self):
        super().call_me()
        print("C")

class D(A):
    def call_me(self):
        super().call_me()
        print("D")

class B:
    def call_me(self):
        print("B")

class E(B):
    def call_me(self):
        super().call_me()
        print("E")

class F(B):
    def call_me(self):
        super().call_me()
        print("F")

class G(C, D, E):
    def call_me(self):
        super().call_me()
        print("G")

class H(F):
    def call_me(self):
        super().call_me()
        print("H")

class I(G, H):
    def call_me(self):
        super().call_me()
        print("I")


user@ubuntu:~/Documents/Python/oop_python$ python3.2 -i tt.py
>>> i = I()
>>> i.call_me()
A
D
C
G
I

Question> Why B, E, F are not printed?

//            updated based on comments from delnan

user@ubuntu:~/Documents/Python/oop_python$ cat tt.py
class BaseClass():
    def call_me(self):
        print("BaseClass")
    pass

class A(BaseClass):
    def call_me(self):
        super().call_me()
        print("A")

class C(A):
    def call_me(self):
        super().call_me()
        print("C")

class D(A):
    def call_me(self):
        super().call_me()
        print("D")

class B(BaseClass):
    def call_me(self):
        super().call_me()
        print("B")

class E(B):
    def call_me(self):
        super().call_me()
        print("E")

class F(B):
    def call_me(self):
        super().call_me()
        print("F")

class G(C, D, E):
    def call_me(self):
        super().call_me()
        print("G")

class H(F):
    def call_me(self):
        super().call_me()
        print("H")

class I(G, H):
    def call_me(self):
        super().call_me()
        print("I")

user@ubuntu:~/Documents/Python/oop_python$ python3.2 -i tt.py
>>> i = I()
>>> i.call_me()
BaseClass
B
F
H
E
A
D
C
G
I

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

吻安 2025-01-01 13:35:57

一个常见的误解是 super() 将调用所有超类方法。不会的。它只会调用其中之一。哪一个是由super()根据一些特定的规则自动计算出来的。有时,它调用的不是实际的超类,而是兄弟类。但不能保证所有类都会被调用,除非所有类都依次使用 super()。

在这种情况下,A和B没有调用super。如果你将它添加到 A,它实际上会调用“丢失”的类,但如果你将它添加到 B,你会得到一个错误,因为在这种特殊情况下,B 最终将成为“最后一个”(或第一个,取决于你如何看待它)类。

如果要使用 super(),最好的解决方案是 A 和 B 有一个公共基类,实现 call_me,但不调用 super()。 (感谢 delnan 的建议)。

但是,如果您知道类层次结构,则可以直接调用超类方法,而不是使用 super()。请注意,在上面的情况下,并不意味着每个类都必须直接调用它的每个基类。因此,当您作为程序员无法完全控制类层次结构时(例如,如果您编写库或混合类),这没有用。那么你必须使用super()。

A common misunderstanding is that super() will call all superclasses methods. It will not. It will call only one of them. Which one is automatically calculated by super() according to some specific rules. Sometimes the one it calls is not an actual super-class, but a sibling. But there is no guarantee that all will be called, unless all of the classes in their turn are using super().

In this case, A and B is not calling super. And if you add it to A, it will in fact call the "missing" classes, but if you add it to B you get an error, because in this particular case, B will end up being the "last" (or first, depending on how you see it) class.

If you want to use super(), the best solution is to have a common baseclass for A and B that implements call_me, but does not call super(). (Thanks to delnan for suggesting that).

However, if you know your class hierarchy, you can call the superclasses methods directly instead of using super(). Note that this in the case above, doesn't mean that every class must call each of it's baseclasses directly. This is therefore not useful in cases where you as a programmer don't have complete control over the class hierarchy, for example if you write libraries or mixin-classes. Then you have to use super().

眸中客 2025-01-01 13:35:57

使用super的前提是该类必须是new-style

python 中 super 有两种用例:

  1. 单继承的类层次结构,super 可以用来引用父类而无需显式命名

  2. 第二个用例是在动态执行环境中支持协作多重继承。

因此,第二种情况符合您的第二个示例条件。在这种情况下,子类将执行 bfs 遍历 以使确保每个覆盖基类方法仅被调用一次。您的继承树可以按照以下顺序重写为衬垫(遵循bfs遍历从左到右)IGCDAEHFB BaseClass。

super 方法的定义是:

Super(type[,object-or-type])

它将返回一个代理对象,该代理对象将方法调用委托给 type 的父类或同级类。在 python 3.x 中,您可以直接调用 super() ,这与 super(currentClassName, self) 相同。这将得到bfs遍历生成的直接右父类的代理。因此方法 i.call_me() 将被调用为:

I.call_me -> G.call_me-> C.call_me-> D.call_me-> A.call_me-> E.call_me-> H.call_me-> F.call_me-> B.call_me-> BaseClass.call_me

两个示例之间的区别

正如您所问的,为什么第一个示例没有打印 B、E、F,因为继承图不是“菱形图”,这意味着 A.call_me B.call_me 是不同的方法。所以python只选择继承分支之一。

希望这有帮助。您还可以查看 python 类文档 了解更多详细信息

The precondition to use super is the class must be the new-style.

There are two use cases for super in python:

  1. A class hierarchy with single inheritance, super can use to refer to parent class without naming them explicitly

  2. Second use case is support cooperative multiple inheritance in a dynamic execution environment.

So, the second case is matching your second example condition. In this case the subclass will do a bfs traverse to make sure each overwrite base class method is called only once. Your inheritance tree could be rewrite to liner as this order (follow the bfs traverse, left to right) I G C D A E H F B BaseClass.

The definition of the super method is:

Super(type[,object-or-type])

It will return a proxy object that delegates method calls to a parent or sibling class of type. In python 3.x you could call super() directly which is as same as super(currentClassName, self). This will get the proxy of the direct right super|sibling class generated by the bfs traverse. So the method i.call_me() will be called as:

I.call_me -> G.call_me -> C.call_me -> D.call_me -> A.call_me -> E.call_me -> H.call_me -> F.call_me -> B.call_me -> BaseClass.call_me

The difference between the two examples

As you asked why the first example didn't print B, E, F, because the inheritance map is not a "diamond graph" which means the A.call_me B.call_me are different method. So python only choose one of the inheritance branch.

Wish this helpful. You could also check the python class doc for more detail

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文