人人都会AI编程

super () 原理与调用顺序

更新时间:2026-07-12

在 Python 的继承体系中,super() 是用来调用父类方法的工具,但它的工作机制远比“直接调用父类”更精巧。理解它,是写出健壮多继承代码的关键。

super() 的本质

super() 并不返回父类对象,而是返回一个代理对象,它会按照方法解析顺序(MRO)去查找下一个类。

  • 语法:super().init()super(当前类, self).method()
  • 在 Python 3 中,实例方法里可以直接写 super().method(),解释器会自动补全参数。
  • 它依赖于两个核心信息:当前类(从哪里开始往上找)和实例(确定 MRO 的所属类)。

MRO(方法解析顺序)决定调用顺序

MRO 规定了多继承时,属性和方法的查找顺序。Python 使用 C3 线性化算法 计算 MRO,保证结果满足:

  • 子类优先于父类
  • 多个父类按定义时的书写顺序
  • 所有父类都位于子类之后,且不重复

查看 MRO:

class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass

print(D.__mro__)
# (D, B, C, A, object)

调用 super() 时,就从当前类在 MRO 中的位置,往后找下一个类的方法。

为什么用 super() 而不是直接写父类名

直接写 Parent.init(self) 有三个问题:

  1. 硬编码父类名,一旦继承关系改变,需要逐一修改,不利于代码复用。
  2. 多继承时不能保证所有父类的方法都被正确调用——某个父类可能被遗漏或不恰当的多次调用。
  3. 破坏协作式调用链:在多继承下,super() 可以串联起一条完整的初始化链,而显式的父类调用做不到。

经典例子:钻石继承与 super() 的协作

class A:
    def __init__(self):
        print("A")
        super().__init__()

class B(A):
    def __init__(self):
        print("B")
        super().__init__()

class C(A):
    def __init__(self):
        print("C")
        super().__init__()

class D(B, C):
    def __init__(self):
        print("D")
        super().__init__()

D()
# 输出:D B C A

解释:D 的 MRO 是 D -> B -> C -> A -> object。每个类的 init 中都调用 super().init(),从而沿着 MRO 顺序传递,A 只被调用一次,且顺序符合预期。这种模式称为“协作式多继承”,要求所有参与者都使用 super()

注意事项

  • 必须保证 super() 调用的方法存在:如果链条中某一环没有定义要调用的方法,会引发 AttributeError
  • 不要忘记传参数:当 super() 调用 init 时,如果父类需要额外参数,需要传递。通常建议在参数设计上保持兼容,或者用 **kwargs 灵活传递。
  • 慎用 super(cls, obj) 的形式:它允许你跳过 MRO 中的某些类,但这通常是危险信号,可能破坏预期行为。

实用总结

  • 单继承场景下,super() 比硬编码父类名更灵活,修改父类不用改子类代码。
  • 多继承场景下,所有类都应该使用 super() 并保持调用链,不要混用显式父类调用,否则会破坏 MRO 链条。
  • super() 不是“调用父类”,而是“调用 MRO 中的下一个类”。牢记这点,才能理解它在多继承中的真正价值。