
最近遇到到一个问题,super 在多继承的类中只调用第一个类的函数。
代码如下
class A(object): def __init__(self, **kwargs): print('a1') print('a', kwargs) print('a2') class B(object): def __init__(self, **kwargs): print('b1') print('b', kwargs) print('b2') class C(A, B): def __init__(self, **kwargs): print('c1') super(C, self).__init__() print('c2') if __name__ == '__main__': c = C() 结果是
c1
a1
a {}
a2
c2
这就很尴尬了,为什么不会出发 B().init 呢
1 Cooky 2017 年 5 月 18 日 via Android 你觉得你模棱两可的调用,Python 会知道调哪个? |
2 ChangHaoWei OP @Cooky python2 貌似没问题啊 |
3 hareandlion 2017 年 5 月 18 日 via iPhone 按声明时的父类顺序的 |
4 ChangHaoWei OP @hareandlion 你可以自己贴代码去试试,我反正结果是我主题上说的,忽略了第二个超类 |
5 ChangHaoWei OP 更新 ```python class A(): def __init__(self, **kwargs): super().__init__() print('a1') print('a', kwargs) print('a2') class B(): def __init__(self, **kwargs): super().__init__() print('b1') print('b', kwargs) print('b2') class C(A, B): def __init__(self, **kwargs): print('c1') super().__init__() print('c2') if __name__ == '__main__': c = C() ``` 这样的代码就能有下面的输出。。为什么,求有相关研究的高手给我一个答案 ``` c1 b1 b {} b2 a1 a {} a2 c2 ``` |
6 XYxe 2017 年 5 月 18 日 这应该是 MRO 的问题,2.7.13 和 3.5.3 的结果和你的是一样的。 |
7 hareandlion 2017 年 5 月 18 日 ....这是 Python 的 MRO 机制决定的,Python3 用的是 C3 method,看看官方文档吧 |
8 ChangHaoWei OP @XYxe 问题是,为什么会这样,我后面贴出的代码本质上差不多,为什么又能正常的调用所有超类的初始化方法呢? |
9 ChangHaoWei OP @hareandlion 方便的话,麻烦你指点以下。 |
10 XYxe 2017 年 5 月 18 日 @ChangHaoWei #8 两个代码是有区别的。 super 就是查找 mro 的下一个类。C 的 mro:[C, A, B, object],所以你新的代码就是按照这个顺序来调用__init__的。 |
11 Cooky 2017 年 5 月 18 日 via Android @ChangHaoWei A B 里面也要有 super ( |
12 AnyISalIn 2017 年 5 月 18 日 mro |
13 CallMeHoney 2017 年 5 月 18 日 MRO C3 算法,简单来说就是深度优先遍历 |
14 XYxe 2017 年 5 月 18 日 @CallMeHoney #13 不是深度优先遍历。 |
15 zhengxiaowai 2017 年 5 月 18 日 super 并不是调用父类,而是调用 MRO 中的,具体要看 MRO 中顺序 |
16 Readme16 2017 年 5 月 18 日 ```python class A(object): def __init__(self, **kwargs): super().__init__() print('a1') print('a', kwargs) print('a2') class B(object): def __init__(self, **kwargs): print('b1') print('b', kwargs) print('b2') class C(A, B): def __init__(self, **kwargs): print('c1') super().__init__() print('c2') if __name__ == '__main__': c = C() ``` |
17 jiang42 2017 年 5 月 18 日 via iPhone 1. 和 MRO 没关系,楼主说的是 B.__init__未调用 2. super 返回的是一个 delegate class,会去查找父类或者 sibling class,你这个情况在 AC 里用 super 就够了。原始的调用顺序 C 调了 super 找到 A,但是 A 没有调 super,所以没有找到它的 sibling B。 所以 best practice 是所有都用 super 用手机打的字,有点乱…… |
18 jiang42 2017 年 5 月 18 日 via iPhone 也和 MRO 有一丢丢关系啦,但是不是楼上所说的锅全丢给 MRO |
19 hugo775128583 2017 年 5 月 18 日 楼上已经说了 MRO 没毛病 |
20 weyou 2017 年 5 月 18 日 @zhengxiaowai @jiang42 同意两位的意见。 Python 的 super()帮助文档引用了一个链接: http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ 这个文章的结论是 super().method()要能够 work,所有在祖先树上的 class 必须以合作模式来设计,这就是: 1. 被 super()调用的 method()必须存在 2. 调用者和被调用者必须要具有相同的参数(签名) 3. 每个出现的 method()必须也使用了 super() 我加了一些注释,我想这样就比较清楚了。 class A(object): ....def __init__(self, **kwargs): ........super().__init__() # 在 MRO(A,B,object)里面找到了下一级是 B. 调用 B.__init__(这句如果没有 B.__init__就调用不到) ........print('a1') ........print('a', kwargs) ........print('a2') class B(object): ....def __init__(self, **kwargs): ........super().__init__() # 在 MRO(B,object )里面找到了下一级是 object. 调用 object.__init__() ........print('b1') ........print('b', kwargs) ........print('b2') class C(A, B): ....def __init__(self, **kwargs): ........print('c1') ........super().__init__() # 在 MRO(C,A,B,object )里面找到了下一级是 A. . 调用 A.__init__() ........print('c2') if __name__ == '__main__': ....print(C.__mro__) # MRO: (C,A,B,object) ....c = C() |
21 ChangHaoWei OP @weyou 谢谢。幸苦你帮我解决这个问题了。我最近遇到一个 pyqt5 的一个问题,能不能帮我解决? |