Python2.7中super()为何跳过直接父类?方法调用异常求助
问题原因与解决方案
嘿,这个问题其实是对Python里super()的工作原理理解有偏差导致的,我来给你掰扯清楚~
首先看你代码里的关键问题:你在C的bar方法里写了super(B, self).bar(),但这行代码并不是直接调用B类的bar方法,而是在self(也就是C的实例)的方法解析顺序(MRO)中,找到B类之后的下一个类,然后调用它的bar方法。
先确认下C类的MRO(方法解析顺序):执行print(C.__mro__)会得到(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)。当你用super(B, self)时,它会跳过B,直接找MRO里B后面的A,所以最终调用的是A的bar方法,这就是为什么输出是"bar from A"。
正确的解决方案
如果你想调用B类的bar方法,有两种靠谱的写法:
- 推荐:用
super()指定当前类作为起点
Python3里super()可以省略参数,默认会把当前类和self传入,等价于super(C, self):
class A(object): def bar(self): print('bar from A') class B(A): def bar(self): print('bar from B') class C(B): def bar(self): super().bar() # 等价于 super(C, self).bar() c = C() c.bar() # 现在会输出 "bar from B"
这里super(C, self)会在MRO中找到C之后的第一个类(也就是B),调用它的bar方法,完全符合你的预期。
- 备选:显式调用
B类的方法(不推荐多继承场景)
如果你想绕开MRO直接调用B的方法,可以直接写:
class C(B): def bar(self): B.bar(self)
这种写法虽然能得到正确结果,但如果后续继承关系发生变化(比如新增父类),这种硬编码的方式很容易出问题,维护性远不如super()。
一句话总结
super()的第一个参数是用来确定MRO查找的起点,而不是指定要调用的类——它会从这个起点的下一个类开始查找方法。所以一定要根据你想要的MRO位置来选择第一个参数哦。
内容的提问来源于stack exchange,提问作者cgsdfc
相关产品推荐
相关产品推荐

