Python3.6.1 中一个很有趣的问题探讨

最近遇到到一个问题,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


Python3.6.1 中一个很有趣的问题探讨

22 回复

你觉得你模棱两可的调用,Python 会知道调哪个?


我无法理解你的问题。

python2 貌似没问题啊

按声明时的父类顺序的

你可以自己贴代码去试试,我反正结果是我主题上说的,忽略了第二个超类

更新
python<br>class A():<br> def __init__(self, **kwargs):<br> super().__init__()<br> print('a1')<br> print('a', kwargs)<br> print('a2')<br><br><br>class B():<br> def __init__(self, **kwargs):<br> super().__init__()<br> print('b1')<br> print('b', kwargs)<br> print('b2')<br><br><br>class C(A, B):<br> def __init__(self, **kwargs):<br> print('c1')<br> super().__init__()<br> print('c2')<br><br><br>if __name__ == '__main__':<br> c = C()<br>
这样的代码就能有下面的输出。。为什么,求有相关研究的高手给我一个答案
<br>c1<br>b1<br>b {}<br>b2<br>a1<br>a {}<br>a2<br>c2<br>

这应该是 MRO 的问题,2.7.13 和 3.5.3 的结果和你的是一样的。

…这是 Python 的 MRO 机制决定的,Python3 用的是 C3 method,看看官方文档吧

问题是,为什么会这样,我后面贴出的代码本质上差不多,为什么又能正常的调用所有超类的初始化方法呢?

方便的话,麻烦你指点以下。

#8 两个代码是有区别的。
super 就是查找 mro 的下一个类。C 的 mro:[C, A, B, object],所以你新的代码就是按照这个顺序来调用__init__的。

A B 里面也要有 super (

MRO C3 算法,简单来说就是深度优先遍历

#13 不是深度优先遍历。

super 并不是调用父类,而是调用 MRO 中的,具体要看 MRO 中顺序

python<br>class A(object):<br> def __init__(self, **kwargs):<br> super().__init__()<br> print('a1')<br> print('a', kwargs)<br> print('a2')<br> <br><br>class B(object):<br> def __init__(self, **kwargs):<br> print('b1')<br> print('b', kwargs)<br> print('b2')<br><br><br>class C(A, B):<br> def __init__(self, **kwargs):<br> print('c1')<br> super().__init__()<br> print('c2')<br><br><br>if __name__ == '__main__':<br> c = C()<br>

  1. 和 MRO 没关系,楼主说的是 B.__init__未调用
    2. super 返回的是一个 delegate class,会去查找父类或者 sibling class,你这个情况在 AC 里用 super 就够了。原始的调用顺序 C 调了 super 找到 A,但是 A 没有调 super,所以没有找到它的 sibling B。

    所以 best practice 是所有都用 super

    用手机打的字,有点乱……

也和 MRO 有一丢丢关系啦,但是不是楼上所说的锅全丢给 MRO

楼上已经说了 MRO 没毛病



同意两位的意见。

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

谢谢。幸苦你帮我解决这个问题了。我最近遇到一个 pyqt5 的一个问题,能不能帮我解决?

回到顶部