Python 类构造函数:__init__
习惯上把 __init__ 叫作构造函数,严格来说它负责在实例已经创建之后做初始化(设置属性等);对象的实际分配由 object.__new__ 等机制完成。日常表述里「构造函数」多指 __init__,本文沿用这一说法。
语法概要:
def __init__(self, ...):
...- 用
def定义,是类的实例方法。 - 第一个参数为当前实例,惯例命名为
self(见 self 变量)。 - 其余参数可选,用于传入初始数据。
更多「类与对象」背景见 类与对象;单继承、super() 见 类的继承;多重继承见 多重继承。
1. 未定义 __init__ 的类
不写 __init__ 时,实例仍会被创建,使用的是继承链上的默认行为(最终追溯到 object)。
class Data:
pass
d = Data()
print(type(d))输出:
<class '__main__.Data'>子类不写 __init__ 时,会继承父类的 __init__(若父类定义了):
class BaseData:
def __init__(self, i):
print(f"BaseData 构造,参数 {i}")
self.id = i
class Data(BaseData):
pass
d = Data(10)
print(type(d))输出:
BaseData 构造,参数 10
<class '__main__.Data'>2. 无额外参数的 __init__
只有 self 时,常用于统计实例个数、打日志等:
class Data1:
count = 0
def __init__(self):
print("Data1 构造")
Data1.count += 1
d1 = Data1()
d2 = Data1()
print("Data1 实例个数 =", Data1.count)输出:
Data1 构造
Data1 构造
Data1 实例个数 = 23. 带参数的 __init__
最常见:用参数初始化实例属性。
class Data2:
def __init__(self, i, n):
print("Data2 构造")
self.id = i
self.name = n
d2 = Data2(10, "Secret")
print(f"id = {d2.id}, name = {d2.name}")输出:
Data2 构造
id = 10, name = Secret4. 继承与 super()
子类若重写 __init__,通常需要显式调用父类的 __init__,否则父类侧属性可能未初始化。
class Person:
def __init__(self, n):
print("Person 构造")
self.name = n
class Employee(Person):
def __init__(self, i, n):
print("Employee 构造")
super().__init__(n) # 等价于 Person.__init__(self, n)
self.id = i
emp = Employee(99, "Pankaj")
print(f"id = {emp.id}, name = {emp.name}")输出:
Employee 构造
Person 构造
id = 99, name = Pankaj也可写 Person.__init__(self, n);协作式多继承里更推荐 super()(与 MRO 有关)。
5. 多级单继承链
沿继承链逐级 super().__init__(...) 传参:
class A:
def __init__(self, a):
print("A 构造")
self.var_a = a
class B(A):
def __init__(self, a, b):
super().__init__(a)
print("B 构造")
self.var_b = b
class C(B):
def __init__(self, a, b, c):
super().__init__(a, b)
print("C 构造")
self.var_c = c
c_obj = C(1, 2, 3)
print(f"var_a={c_obj.var_a}, var_b={c_obj.var_b}, var_c={c_obj.var_c}")输出:
A 构造
B 构造
C 构造
var_a=1, var_b=2, var_c=36. 多重继承:显式调用各父类 __init__
多重继承时,除了用 super() 按 MRO 做协作链式调用外,教学与部分场景下也会逐个写 父类.__init__(self, ...),确保每个直接基类都完成初始化(具体项目需结合 MRO 与「协作式 super()」约定,详见 多重继承)。
class A1:
def __init__(self, a1):
print("A1 构造")
self.var_a1 = a1
class B1:
def __init__(self, b1):
print("B1 构造")
self.var_b1 = b1
class C1(A1, B1):
def __init__(self, a1, b1, c1):
print("C1 构造")
A1.__init__(self, a1)
B1.__init__(self, b1)
self.var_c1 = c1
c_obj = C1(1, 2, 3)
print(f"var_a1={c_obj.var_a1}, var_b1={c_obj.var_b1}, var_c1={c_obj.var_c1}")输出:
C1 构造
A1 构造
B1 构造
var_a1=1, var_b1=2, var_c1=3不能有多个 __init__(重载)
Python 不支持像 Java 那样多个同名构造函数。若类里写两个 __init__,后者会覆盖前者:
class D:
def __init__(self, x):
print(f"构造 1: {x}")
def __init__(self, x, y):
print(f"构造 2: {x}, {y}")
D(10, 20)需要多种创建方式时,可用 @classmethod 工厂方法、默认参数、*args / **kwargs 等,而不是重复定义 __init__。
__init__ 的返回值
__init__ 必须不返回非 None 的值;若 return 了其它对象,会触发 TypeError。
class Data:
def __init__(self, i):
self.id = i
return True
d = Data(10)运行会得到:
TypeError: __init__() should return None, not 'bool'可以 return None 或省略 return(默认即为 None)。
小结
__init__(self, ...)在实例创建后初始化状态;第一个参数为self。- 子类重写
__init__时一般要调用父类__init__(super()或父类.__init__(self, ...))。 - 不能通过多个
__init__实现重载;__init__不能返回非None。