本文目录导读:
super() 函数在 Python 中主要用于调用父类(超类)的方法,它的核心作用是实现合作式多重继承,确保在多条继承链上,每个类的方法都能被正确调用一次(通过 MRO 算法)。
super() 返回一个代理对象,让你可以调用父类或其他共同祖先类的方法,而无需显式指定父类的名字。
主要作用场景
单继承:避免硬编码父类名,便于维护
最直观的用途是在子类中继承并扩展父类的方法(__init__)。
不用 super 的写法(硬编码):
class Parent:
def __init__(self, name):
self.name = name
class Child(Parent):
def __init__(self, name, age):
Parent.__init__(self, name) # 显式调用父类,写死了类名
self.age = age
- 缺点:如果将来
Parent类名变了,或者需要改成多重继承,这行代码必须跟着改。
用 super 的写法(推荐):
class Child(Parent):
def __init__(self, name, age):
super().__init__(name) # 动态根据 MRO 调用父类,无需指定类名
self.age = age
- 优点:当父类发生变化时,子类代码无需修改。
多重继承:按 MRO 顺序调用所有父类,避免重复调用
这是 super() 最核心、也是初学者最容易迷惑的地方,在多重继承下,super() 不是仅仅调用“直接父类”,而是根据方法解析顺序调用下一个类。
经典案例(菱形继承):
class A:
def __init__(self):
print("A.__init__")
super().__init__() # A 的父类是 object
class B(A):
def __init__(self):
print("B.__init__")
super().__init__() # 调用 A 的 __init__
class C(A):
def __init__(self):
print("C.__init__")
super().__init__() # 调用 A 的 __init__
class D(B, C):
def __init__(self):
print("D.__init__")
super().__init__() # 调用 B 的 __init__
d = D()
输出结果:
D.__init__
B.__init__ # 先走 B
C.__init__ # 然后通过 B 的 super 走到 C(而不是直接走 A)
A.__init__ # 最后通过 C 的 super 走到 A
关键点:super() 遵循 D 类的 MRO 顺序:
D -> B -> C -> A -> object
- 如果不用
super()而硬编码B.__init__(),则可能跳过C的初始化,或导致A被初始化两次。 super()保证了在复杂继承中,每个类的__init__只被执行一次,且顺序正确。
super() 的使用细节
常见用法
class Child(Parent):
def method(self):
super().method() # 无参数调用,Python 3 自动传递当前类和 self
带参数的完整形式(通常不需要手动写)
super(Child, self).method() # Python 2 常用,Python 3 可省略为 super().method()
一个实际例子:子类扩展父类方法
假设有一个 Vehicle 类,Car 继承自它:
class Vehicle:
def start(self):
print("Vehicle engine starts")
class Car(Vehicle):
def start(self):
super().start() # 先调用父类的 start
print("Car's alarm chimes") # 再添加子类的行为
my_car = Car()
my_car.start()
输出:
Vehicle engine starts
Car's alarm chimes
什么时候必须用 super()?
- 需要在子类中调用父类的原方法并扩展它(如
__init__、save等)。 - 涉及多重继承,尤其是可能产生钻石继承或继承链较复杂时。
- 想写出健壮、可维护、可扩展的面向对象代码。
一句话记住:super() 让你在继承中“向上”调用,但具体调用哪个类,由 MRO 动态决定。
标签: 避免菱形继承