建平12138 2020-07-14 21:57 采纳率: 100%
浏览 116
已采纳

对python在子类中通过“super”方法调用父类的过程的疑惑

对python在子类中通过“super”方法调用父类的过程的疑惑

为什么像第二种,就没有进入C,离开C了;第三种没有进入,离开A了

第一种:

class A():
    def __init__(self):
        print("进入A…")
        print("离开A…")

class B(A):
    def __init__(self):
        print("进入B…")
        super().__init__()
        print("离开B…")

class C(A):
    def __init__(self):
        print("进入C…")
        super().__init__()
        print("离开C…")

class D(B, C):
    def __init__(self):
        print("进入D…")
        super().__init__()
        print("离开D…")

d = D()

第一种结果:

进入D…
进入B…
进入C…
进入A…
离开A…
离开C…
离开B…
离开D…

第二种:

class A():
    def __init__(self):
        print("进入A…")
        print("离开A…")

class B(A):
    def __init__(self):
        print("进入B…")
        print("离开B…")

class C(A):
    def __init__(self):
        print("进入C…")
        super().__init__()
        print("离开C…")

class D(B, C):
    def __init__(self):
        print("进入D…")
        super().__init__()
        print("离开D…")

d = D()

第二种结果:

进入D…
进入B…
离开B…
离开D…

第三种:

class A():
    def __init__(self):
        print("进入A…")
        print("离开A…")

class B(A):
    def __init__(self):
        print("进入B…")
        super().__init__()
        print("离开B…")

class C(A):
    def __init__(self):
        print("进入C…")
        print("离开C…")

class D(B, C):
    def __init__(self):
        print("进入D…")
        super().__init__()
        print("离开D…")

d = D()

第三种结果:

进入D…
进入B…
进入C…
离开C…
离开B…
离开D…
  • 写回答

1条回答 默认 最新

  • Valtava 2020-07-15 01:32
    关注

    了解这种现象需要以下两点:

    1. super() 返回的是一个代理对象,使得子类可以调用父类的方法,这个可以查看官方文档

    2. Python 中存在完整定义的函数查找顺序 (非标准翻译,原文 Method Resolution Order,MRO, 见这个链接)

    简单来说,就是调用 super().__ini__() 只是依据MRO查找相应的对象,找到存在目标方法的对象后即调用该对象的方法并**停止本轮查找**,而不会像一眼看过去可能会认为的那样“逐级初始化”父类

    MRO可以通过 class property __mro__ 检查

    D.__mro__
    

    针对你的例子,第一个例子里,其MRO,即查找顺序为 D, B, C, A (你的3个例子 MRO 是一样的)
    每次使用 super() 会使得查找起点从当前往右移动一格,即在 D 内调用 super().__init__() 将从B开始查找,由于B定义了__init__() 方法,本轮查找结束。然而B.__init__()内调用了super().__init__(),使得Python再次依据MRO进行查找,这次从C开始(B 往右一格)查找,由于 C 定义了__init__(), 本轮结束,但是C.__init__() 内部调用了 super().__init__() 再次使得Python基于同样的逻辑调用 A 的__init__(),所以你看到的是

    进入D…
    进入B…
    进入C…
    进入A…
    离开A…
    离开C…
    离开B…
    离开D…
    

    而不是进入B后进入A这种看上去似乎是“逐级递进”的调用方式

    第二个例子中,基于同样的原则,在 D 的 __init__() 中调用 super().__init__(),到B的时候本轮查找结束,由于 B 的__init__() 方法不再创建新的调用链条,调用栈到此结束;第三个例子理由一致,你试试自己理解下第三个例子?

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 树莓派安卓APK系统签名
  • ¥15 maple软件,用solve求反函数出现rootof,怎么办?
  • ¥65 汇编语言除法溢出问题
  • ¥15 Visual Studio问题
  • ¥20 求一个html代码,有偿
  • ¥100 关于使用MATLAB中copularnd函数的问题
  • ¥20 在虚拟机的pycharm上
  • ¥15 jupyterthemes 设置完毕后没有效果
  • ¥15 matlab图像高斯低通滤波
  • ¥15 针对曲面部件的制孔路径规划,大家有什么思路吗