super() 是什么?
super() 是一个内置函数,它返回一个代理对象,这个代理对象允许你调用父类(或超类)的方法。

它的主要用途是:
- 解决多重继承问题:在复杂的继承结构中,
super()可以确保按照正确的方法解析顺序 来调用父类的方法。 - 避免硬编码父类名:使用
super()调用父类方法时,不需要显式地写出父类的名称,这使得代码更具可维护性,如果将来修改了类的继承关系,只需要改变class语句的父类列表即可,而不需要修改内部所有Parent.method()的调用。
基础用法:单继承场景
在单继承中,super() 的作用相对简单,主要是为了代码的规范和一致性,并方便未来扩展。
实例 1:在子类中调用父类的 __init__ 方法
这是最常见的用法,子类在初始化时,需要先调用父类的初始化方法来设置父类定义的属性。
class Animal:
def __init__(self, name):
print("Animal 的 __init__ 被调用")
self.name = name
def speak(self):
print(f"{self.name} makes a sound.")
class Dog(Animal):
def __init__(self, name, breed):
print("Dog 的 __init__ 被调用")
# 使用 super() 调用父类 Animal 的 __init__ 方法
super().__init__(name)
self.breed = breed
print(f"一只名为 {self.name} 的 {self.breed} 狗被创建了。")
# 创建一个 Dog 实例
my_dog = Dog("旺财", "中华田园犬")
# 调用 speak 方法
my_dog.speak()
输出:

Dog 的 __init__ 被调用
Animal 的 __init__ 被调用
一只名为 旺财 的 中华田园犬 狗被创建了。
旺财 makes a sound.
代码解析:
- 当创建
Dog("旺财", "中华田园犬")时,Dog类的__init__方法被调用。 - 在
Dog.__init__内部,super().__init__("旺财")这行代码会找到Dog的父类Animal,并调用其__init__方法。 Animal.__init__执行完毕后,程序返回到Dog.__init__,继续执行self.breed = breed等后续代码。- 这样,
Dog实例就同时拥有了name(来自父类)和breed(来自子类)属性。
进阶用法:多重继承场景
super() 的真正威力体现在多重继承中,Python 使用 C3 线性化算法来确定方法调用的顺序,super() 严格遵循这个顺序。
实例 2:钻石继承问题
钻石继承(菱形继承)是多重继承中的一个经典场景。
class A:
def do_something(self):
print("A 的 do_something")
class B(A):
def do_something(self):
print("B 的 do_something")
super().do_something() # 调用 A 的 do_something
class C(A):
def do_something(self):
print("C 的 do_something")
super().do_something() # 调用 A 的 do_something
class D(B, C):
def do_something(self):
print("D 的 do_something")
super().do_something() # 调用 B 的 do_something
# 创建 D 的实例并调用方法
d_instance = D()
d_instance.do_something()
输出:

D 的 do_something
B 的 do_something
C 的 do_something
A 的 do_something
代码解析:
- 方法解析顺序:对于
D类,其 MRO 是D -> B -> C -> A -> object,你可以用print(D.__mro__)查看。 - 调用链:
d_instance.do_something()首先执行D中的打印语句。- 然后遇到
super().do_something()。super()会沿着 MRO 找到D的下一个类,即B。 - 执行
B中的do_something,打印语句后,又遇到super().do_something()。super()会从B的下一个类开始找,即C(注意:不是直接回A,因为C也是B的“兄弟”路径)。 - 执行
C中的do_something,打印语句后,又遇到super().do_something()。super()从C的下一个类开始找,即A。 - 最后执行
A中的do_something。
这个例子完美展示了 super() 如何在复杂的继承结构中“按图索骥”,确保每个父类的方法只被调用一次,并且顺序符合逻辑。
super() 的两种形式
super() 有两种常见的调用形式,在 Python 3 中,第一种形式(无参数)是首选和最推荐的。
super().method() (推荐)
这是最简洁、最现代的用法,它自动处理了类和实例的传递。
class Parent:
def greet(self):
print("你好,我是父类。")
class Child(Parent):
def greet(self):
print("你好,我是子类。")
super().greet() # 自动将 self 作为参数传递
c = Child()
c.greet()
# 输出:
# 你好,我是子类。
# 你好,我是父类。
super(Child, self).method() (传统)
这种形式明确指定了当前类和实例,在 Python 2 中很常见,因为 Python 2 的 super() 需要这两个参数,在 Python 3 中,这种写法仍然有效,但通常被认为是冗余的。
class Child(Parent):
def greet(self):
print("你好,我是子类。")
# 明确指定了子类 Child 和实例 self
super(Child, self).greet()
c = Child()
c.greet()
# 输出与上面相同
一个实际的、有用的例子:super() 与 __str__
假设你有一个基类 Person,你想为它创建一个字符串表示,然后你创建一个 Employee 类,它继承自 Person,并希望在其字符串表示中包含额外的信息,同时保留父类的信息。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
# 返回一个基础的字符串表示
return f"Person: {self.name}, Age: {self.age}"
class Employee(Person):
def __init__(self, name, age, employee_id):
# 1. 调用父类的 __init__ 来初始化 name 和 age
super().__init__(name, age)
self.employee_id = employee_id
def __str__(self):
# 2. 调用父类的 __str__ 获取基础信息,然后添加子类信息
base_info = super().__str__()
return f"{base_info}, Employee ID: {self.employee_id}"
# 创建实例
p = Person("张三", 30)
e = Employee("李四", 28, "E12345")
print(p)
# 输出: Person: 张三, Age: 30
print(e)
# 输出: Person: 李四, Age: 28, Employee ID: E12345
在这个例子中,Employee 类通过 super().__str__() 获取了 Person 类精心编写的字符串格式化逻辑,然后在此基础上进行扩展,而不是重复编写代码,这是 super() 的一个绝佳应用。
总结与最佳实践
- 主要用途:在子类中调用父类的方法,尤其是在
__init__、__str__等特殊方法中,以及在多重继承中。 - 核心优势:
- 遵循 MRO:正确处理复杂继承关系。
- 代码解耦:不依赖父类的具体名称,易于维护和重构。
- Python 3 推荐用法:始终使用
super().method()的无参数形式。 - 何时使用:当你想在子类中扩展而不是完全替换父类功能时,都应该使用
super(),如果你确实想完全阻止父类方法的执行(不推荐),那就直接不调用super()即可。
