核心要点
在 Python 中,子类的 __init__ 方法默认不会自动调用父类的 __init__ 方法,如果你希望在创建子类实例时,先执行父类的初始化逻辑(设置父类共有的属性),你必须在子类的 __init__ 方法中显式地调用父类的 __init__ 方法。

为什么需要调用父类的 __init__?
父类的 __init__ 方法通常用于初始化该类实例所必需的属性,子类继承了父类的属性和方法,但子类实例本身并没有执行父类的 __init__ 代码,因此这些属性并未被正确初始化。
让我们看一个没有调用父类 __init__ 的例子:
class Animal:
def __init__(self, name, species):
print("Animal 的 __init__ 被调用")
self.name = name
self.species = species
def make_sound(self):
print("动物发出声音")
class Dog(Animal):
def __init__(self, name, breed, color):
print("Dog 的 __init__ 被调用")
self.breed = breed
self.color = color
# 创建一个 Dog 实例
my_dog = Dog("旺财", "中华田园犬", "黄色")
# 尝试访问父类的属性
try:
print(my_dog.name) # 这会报错!
except AttributeError as e:
print(f"错误: {e}")
# 尝试调用父类的方法
my_dog.make_sound() # 这可以工作,因为方法已经被继承了
输出:
Dog 的 __init__ 被调用
错误: 'Dog' object has no attribute 'name'
动物发出声音
分析:

- 当我们创建
my_dog实例时,只有Dog类的__init__方法被调用了。 Animal类的__init__方法从未被执行,self.name和self.species这两个属性没有被创建。- 当我们尝试访问
my_dog.name时,Python 找不到这个属性,抛出AttributeError。 make_sound方法之所以能调用,是因为方法是通过继承机制传递下来的,它不需要在实例化时“创建”。
如何正确调用父类的 __init__?
我们有几种方式可以调用父类的 __init__ 方法,最常用和推荐的是使用 super()。
使用 super() (推荐)
super() 是一个内置函数,它返回一个代理对象,该对象允许你调用父类(或兄弟类)的方法,这是现代 Python(Python 3)中最标准、最清晰的方式。
语法:
super().父类方法名(参数列表)
示例:

class Animal:
def __init__(self, name, species):
print("Animal 的 __init__ 被调用")
self.name = name
self.species = species
def make_sound(self):
print("动物发出声音")
class Dog(Animal):
def __init__(self, name, breed, color):
print("Dog 的 __init__ 被调用")
# 使用 super() 调用父类 Animal 的 __init__ 方法
# 注意:这里 self 会自动传递给父类
super().__init__(name, species="犬科") # 我们可以在这里显式指定 species
self.breed = breed
self.color = color
# 创建一个 Dog 实例
my_dog = Dog("旺财", "中华田园犬", "黄色")
# 现在可以成功访问父类的属性了
print(f"名字: {my_dog.name}")
print(f"种类: {my_dog.species}")
print(f"品种: {my_dog.breed}")
print(f"颜色: {my_dog.color}")
# 调用父类的方法
my_dog.make_sound()
输出:
Dog 的 __init__ 被调用
Animal 的 __init__ 被调用
名字: 旺财
种类: 犬科
品种: 中华田园犬
颜色: 黄色
动物发出声音
分析:
Dog的__init__执行print("Dog 的 __init__ 被调用")。super().__init__(name, species="犬科")这行代码,将my_dog实例(即self)以及name和"犬科"作为参数,传递给了Animal类的__init__方法。Animal的__init__执行,并设置了name和species属性。- 然后继续执行
Dog的__init__,设置breed和color属性。 my_dog实例拥有了所有需要的属性。
直接调用父类名 (旧式方法,不推荐)
在 Python 2 中或者一些旧的代码中,你可能还会看到这种方式。
语法:
父类名.__init__(self, 参数列表)
示例:
class Dog(Animal):
def __init__(self, name, breed, color):
print("Dog 的 __init__ 被调用")
# 直接调用父类名
Animal.__init__(self, name, species="犬科")
self.breed = breed
self.color = color
为什么不推荐?
- 可读性差:代码中硬编码了父类名,如果将来父类名改变,所有子类中的调用都需要修改。
- 处理多重继承时复杂:在涉及多重继承的复杂场景下,
super()能更好地处理方法解析顺序,而直接调用父类名可能会导致混乱。 - 不够优雅:
super()是 Python 为继承设计的专用工具,更符合语言的设计哲学。
多重继承中的 super()
super() 在多重继承中尤其强大,它能正确地遵循 MRO (Method Resolution Order),即方法解析顺序,来依次调用各个父类的方法。
示例:
class A:
def __init__(self):
print("A 的 __init__")
super().__init__() # 关键:调用下一个 in line 的类的 __init__
class B:
def __init__(self):
print("B 的 __init__")
super().__init__()
class C:
def __init__(self):
print("C 的 __init__")
super().__init__()
class D(A, B, C):
def __init__(self):
print("D 的 __init__")
super().__init__()
print(D.__mro__) # 查看 MRO 顺序
# 输出: (<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
d = D()
输出:
(<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
D 的 __init__
A 的 __init__
B 的 __init__
C 的 __init__
分析:
D.__init__被调用。super().__init__()会找到 MRO 中的下一个类,即A,并调用A.__init__()。A.__init__()中的super().__init__()会找到 MRO 中的下一个类,即B,并调用B.__init__()。B.__init__()中的super().__init__()会找到 MRO 中的下一个类,即C,并调用C.__init__()。C.__init__()中的super().__init__()会找到 MRO 中的下一个类,即object,并调用object.__init__()(object的__init__通常是空的,所以没有输出)。- 整个调用链完成。
这个机制确保了每个父类的初始化逻辑都能被按顺序执行。
总结与最佳实践
- 默认不调用:子类的
__init__不会自动执行父类的__init__。 - 必须显式调用:如果子类需要父类的属性被正确初始化,必须在子类的
__init__中显式调用父类的__init__。 - 首选
super():始终使用super().__init__(...)来调用父类的初始化方法,这是最清晰、最灵活、最符合现代 Python 风格的做法。 - 传递
self:通过super()调用时,self会自动传递,你只需要提供父类__init__方法所需的其他参数。 - 考虑所有参数:在设计类时,一个好的实践是让子类的
__init__方法接收所有必要的参数,并将其中一部分传递给父类的__init__。
一个健壮的子类 __init__ 模板:
class Parent:
def __init__(self, parent_param1, parent_param2):
self.parent_param1 = parent_param1
self.parent_param2 = parent_param2
class Child(Parent):
def __init__(self, parent_param1, parent_param2, child_param):
# 1. 调用父类的 __init__,并传递它需要的参数
super().__init__(parent_param1, parent_param2)
# 2. 初始化子类特有的属性
self.child_param = child_param
# 使用
child_instance = Child("p1_value", "p2_value", "c_value")
print(child_instance.parent_param1) # 输出: p1_value
print(child_instance.child_param) # 输出: c_value 