鱼C论坛

 找回密码
 立即注册
查看: 1691|回复: 12

[已解决]求助super

[复制链接]
发表于 2020-3-15 14:06:40 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
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()

为什么结果里面没有B里调用的super也就是进入A,离开A了
最佳答案
2020-3-15 16:17:45
本帖最后由 sunrise085 于 2020-3-15 18:06 编辑

这是多重继承时初始化函数__init__()的内容,这个涉及到super()和__mro__的用法。
在继承的时候,子类中若需要调用父类的__init__()函数,则需要用super().__init__()。但若是多重继承,什么时候调用哪一个父类的__init__()函数,是由__mro__列表顺序给出的。

在你的这个程序中,D类的__mro__表如下:
<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>
当创建D类的实例化时,会先调用D类的__init__()函数。之后每遇到一次super().__init__()函数就会从上表 中向后找一个父类去执行它的__init__()函数,一直到列表为空或者最后一个执行的__init__()函数中没有super()__init__()函数为止。
我们现在看一下你的程序执行过程:先执行D的__init__()函数,遇到super;然后去执行B的__init__()函数,再次遇到super;接着去执行C的__init__()函数,C中没有遇到super函数,执行完毕之后返回B的__init__()函数;然后返回D的__init__()函数,结束。

假如,C中有super,而B中没有super。那么结果会更短,从D的__init__()函数进入B的__init__()函数,然后返回D的__init__()函数,结束。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-3-15 16:17:45 | 显示全部楼层    本楼为最佳答案   
本帖最后由 sunrise085 于 2020-3-15 18:06 编辑

这是多重继承时初始化函数__init__()的内容,这个涉及到super()和__mro__的用法。
在继承的时候,子类中若需要调用父类的__init__()函数,则需要用super().__init__()。但若是多重继承,什么时候调用哪一个父类的__init__()函数,是由__mro__列表顺序给出的。

在你的这个程序中,D类的__mro__表如下:
<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>
当创建D类的实例化时,会先调用D类的__init__()函数。之后每遇到一次super().__init__()函数就会从上表 中向后找一个父类去执行它的__init__()函数,一直到列表为空或者最后一个执行的__init__()函数中没有super()__init__()函数为止。
我们现在看一下你的程序执行过程:先执行D的__init__()函数,遇到super;然后去执行B的__init__()函数,再次遇到super;接着去执行C的__init__()函数,C中没有遇到super函数,执行完毕之后返回B的__init__()函数;然后返回D的__init__()函数,结束。

假如,C中有super,而B中没有super。那么结果会更短,从D的__init__()函数进入B的__init__()函数,然后返回D的__init__()函数,结束。

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +3 收起 理由
HMartin + 5 + 5 + 3 讲解得十分透彻与耐心

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-15 16:29:48 | 显示全部楼层
我看你之前好像还发过关于这个知识点的帖子。
我再说一些我从其他地方看到的以及一些个人的理解,不一定都正确哈。

多重继承的时候还可以不按照__mro__的顺序执行,可以跳过某个或者某几个去执行。这就是super().__init__()函数的参数设置了。
super().__init__()函数本来是有参数的,长这个样子的,super(类名,self).__init__()函数
根据__mro__列表,若打算跳过哪一个类去执行,super的参数就写哪一个类。
你可以尝试一下我写的这个小程序,修改一下super的参数,或者修改一下不同类中的super。看看会有什么结果。
你的这个继承有点简单,来个复杂一点的。
1.jpg
class A():
    def __init__(self):
        print("进入A…")
        print("离开A…")

class G():
    def __init__(self):
        print("进入G…")
        print("离开G…")
        
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__()
        super(A,self).__init__()
        print("离开D…")

class E(G):
    def __init__(self):
        print("进入E…")
        #super().__init__()
        super(C,self).__init__()
        print("离开E…")

class F(E,D):
    def __init__(self):
        print("进入F…")
        super().__init__()
        #super(G,self).__init__()
        print("离开F…")        
print(F.__mro__)
d = F()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-15 17:52:50 | 显示全部楼层
sunrise085 发表于 2020-3-15 16:17
这是多重继承时初始化函数__init__()的内容,这个涉及到super()和__mro__的用法。
在继承的时候,子类中若 ...

请问B里面的super为什么不立即执行(也就是打印进入A,离开A),而是转去C里面去执行C的init了,是因为mro是按照DBCA顺序来的是吗?
你说的 “之后每遇到一次super().__init__()函数就会从上表 中向后找一个父类去执行它的__init__()函数,一直到列表为空或者最后一个执行的__init__()函数中没有super()__init__()函数为止。”是怎么理解呢?感觉super挺特殊的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-15 17:55:21 | 显示全部楼层
sunrise085 发表于 2020-3-15 16:17
这是多重继承时初始化函数__init__()的内容,这个涉及到super()和__mro__的用法。
在继承的时候,子类中若 ...

C的下面不是def __init__ 吗?为什么会说没有遇到__init__函数呢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-15 18:05:12 | 显示全部楼层
HMartin 发表于 2020-3-15 17:52
请问B里面的super为什么不立即执行(也就是打印进入A,离开A),而是转去C里面去执行C的init了,是因为mro ...

分解一下你的程序吧。
先把D类的__mro__写出来:<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>

d=D(),对D进行实例化,执行D的初始化函数,即D类中的 __init__(self),
print("进入D…"),之后遇到super().__init__(),执行父类初始化函数,从__mro__列表查下一个需要执行初始化的一个父类;
        查到了class B,执行B的初始化函数,即B类中的 __init__(self),
        print("进入B…"),之后遇到super().__init__(),执行父类初始化函数,从__mro__列表查下一个需要执行初始化的一个父类;
                查到了class C,执行B的初始化函数,即C类中的 __init__(self),
                print("进入C…"),print("离开C…")
                C类初始化函数执行完成,返回B类的初始化函数;
        print("离开B…")
        B类初始化函数执行完成,返回D类的初始化函数;
print("离开D…")
实例化对象d初始化完成。
程序结束。
建议你在多看几遍我在二楼和三楼写的内容,可能会有助于你理解super的用法。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-15 18:06:36 | 显示全部楼层
HMartin 发表于 2020-3-15 17:55
C的下面不是def __init__ 吗?为什么会说没有遇到__init__函数呢

哦哦,写错了是C中没遇到super。刚刚改过来了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-15 18:19:11 | 显示全部楼层
sunrise085 发表于 2020-3-15 18:05
分解一下你的程序吧。
先把D类的__mro__写出来:, , , ,

B中的super实际上是执行的是D的父类?我一直以为B中的super就要去执行B的父类也就是去调用A了。
那请问在C中加上super是不是可以这样理解:
先执行D中init,print 进入D,然后执行super;来到B并执行B的init,print 进入B,遇到super;执行D的下一个父类C,于是print 进入C,这时遇到了C中的super,但是D的父类执行完了,但B,C是有父类A的,那么这时候的super就该执行B,C的父类也就是A了;于是进入A,离开A,再离开C,离开B,再离开D。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-15 18:27:35 | 显示全部楼层
HMartin 发表于 2020-3-15 18:19
B中的super实际上是执行的是D的父类?我一直以为B中的super就要去执行B的父类也就是去调用A了。
那请问 ...

不能这样理解,不是说D的父类执行完了,才去执行BC的父类。
应该是按照D的__mro__列表按顺序执行的。
你试一下我在3楼写的更加复杂继承程序,修改相关参数,多尝试几次。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-15 19:02:32 | 显示全部楼层
sunrise085 发表于 2020-3-15 18:27
不能这样理解,不是说D的父类执行完了,才去执行BC的父类。
应该是按照D的__mro__列表按顺序执行的。
...

奥 就是说super没有规定是调用谁的父类,只要是父类,就会依照他们在mro中的顺序依次调用是吧?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-15 19:09:08 | 显示全部楼层
HMartin 发表于 2020-3-15 19:02
奥 就是说super没有规定是调用谁的父类,只要是父类,就会依照他们在mro中的顺序依次调用是吧?

是的。多重继承,最下层的子类有多个父类,但是多个父类之间可能有继承关系也可能没有继承关系,具体执行哪一个父类的初始化函数,由__mro__决定,其实调用super()时的参数也有部分决定权,请看三楼。

注意,学习编程不能一直问别人,自己多编程,多看。请按照三楼给你写的多多尝试,看其结果的变化。自己好好分析一下吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-15 19:50:53 | 显示全部楼层
sunrise085 发表于 2020-3-15 19:09
是的。多重继承,最下层的子类有多个父类,但是多个父类之间可能有继承关系也可能没有继承关系,具体执行 ...

好的,跪谢大佬。我之前就是搞不懂super函数的原理,看到你写的解题步骤就十分透彻了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-15 19:58:34 | 显示全部楼层
HMartin 发表于 2020-3-15 19:50
好的,跪谢大佬。我之前就是搞不懂super函数的原理,看到你写的解题步骤就十分透彻了。

不用客气。解答的过程也是自我学习的一种过程。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-22 18:24

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表