Skip to content

Python 类构造函数:__init__

习惯上把 __init__ 叫作构造函数,严格来说它负责在实例已经创建之后初始化(设置属性等);对象的实际分配由 object.__new__ 等机制完成。日常表述里「构造函数」多指 __init__,本文沿用这一说法。

语法概要:

python
def __init__(self, ...):
    ...
  • def 定义,是类的实例方法
  • 第一个参数为当前实例,惯例命名为 self(见 self 变量)。
  • 其余参数可选,用于传入初始数据。

更多「类与对象」背景见 类与对象;单继承、super()类的继承;多重继承见 多重继承

1. 未定义 __init__ 的类

不写 __init__ 时,实例仍会被创建,使用的是继承链上的默认行为(最终追溯到 object)。

python
class Data:
    pass


d = Data()
print(type(d))

输出:

text
<class '__main__.Data'>

子类不写 __init__ 时,会继承父类的 __init__(若父类定义了):

python
class BaseData:
    def __init__(self, i):
        print(f"BaseData 构造,参数 {i}")
        self.id = i


class Data(BaseData):
    pass


d = Data(10)
print(type(d))

输出:

text
BaseData 构造,参数 10
<class '__main__.Data'>

2. 无额外参数的 __init__

只有 self 时,常用于统计实例个数、打日志等:

python
class Data1:
    count = 0

    def __init__(self):
        print("Data1 构造")
        Data1.count += 1


d1 = Data1()
d2 = Data1()
print("Data1 实例个数 =", Data1.count)

输出:

text
Data1 构造
Data1 构造
Data1 实例个数 = 2

3. 带参数的 __init__

最常见:用参数初始化实例属性

python
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}")

输出:

text
Data2 构造
id = 10, name = Secret

4. 继承与 super()

子类若重写 __init__,通常需要显式调用父类__init__,否则父类侧属性可能未初始化。

python
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}")

输出:

text
Employee 构造
Person 构造
id = 99, name = Pankaj

也可写 Person.__init__(self, n);协作式多继承里更推荐 super()(与 MRO 有关)。

5. 多级单继承链

沿继承链逐级 super().__init__(...) 传参:

python
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}")

输出:

text
A 构造
B 构造
C 构造
var_a=1, var_b=2, var_c=3

6. 多重继承:显式调用各父类 __init__

多重继承时,除了用 super()MRO 做协作链式调用外,教学与部分场景下也会逐个父类.__init__(self, ...),确保每个直接基类都完成初始化(具体项目需结合 MRO 与「协作式 super()」约定,详见 多重继承)。

python
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}")

输出:

text
C1 构造
A1 构造
B1 构造
var_a1=1, var_b1=2, var_c1=3

不能有多个 __init__(重载)

Python 不支持像 Java 那样多个同名构造函数。若类里写两个 __init__后者会覆盖前者

python
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

python
class Data:
    def __init__(self, i):
        self.id = i
        return True


d = Data(10)

运行会得到:

text
TypeError: __init__() should return None, not 'bool'

可以 return None 或省略 return(默认即为 None)。

小结

  • __init__(self, ...) 在实例创建后初始化状态;第一个参数为 self
  • 子类重写 __init__ 时一般要调用父类 __init__super()父类.__init__(self, ...))。
  • 不能通过多个 __init__ 实现重载;__init__ 不能返回非 None

参考