在 Python 的 dataclasses
模块中,__post_init__
方法用于在数据类(Data Class)实例化后执行额外的初始化操作。当你使用 @dataclass
装饰器定义类时,自动生成的 __init__
方法会初始化所有字段,之后会自动调用 __post_init__
(如果定义了该方法)。
基本用法
- 定义数据类:使用
@dataclass
装饰器。 - 实现
__post_init__
:在该方法中编写后初始化逻辑,例如验证数据、动态计算字段值等。
示例代码
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
birth_year: int = None # 需要动态计算的字段
def __post_init__(self):
# 根据 age 计算 birth_year
self.birth_year = 2023 - self.age
# 使用示例
p = Person(name="Alice", age=30)
print(p.birth_year) # 输出 1993
常见场景
1. 验证数据
在 __post_init__
中检查字段合法性:
@dataclass
class Rectangle:
width: float
height: float
def __post_init__(self):
if self.width <= 0 or self.height <= 0:
raise ValueError("Width and height must be positive.")
2. 动态计算字段
若某些字段需要基于其他字段计算(且不需要用户手动初始化),可以使用 init=False
并配合 __post_init__
:
from dataclasses import dataclass, field
@dataclass
class Circle:
radius: float
area: float = field(init=False) # 不包含在自动生成的 __init__ 中
def __post_init__(self):
self.area = 3.14 * self.radius ** 2
# 使用示例
c = Circle(radius=5)
print(c.area) # 输出 78.5
3. 处理继承
如果数据类继承自其他数据类,需手动调用父类的 __post_init__
:
@dataclass
class Base:
id: int
def __post_init__(self):
print("Base post-init")
@dataclass
class Child(Base):
name: str
def __post_init__(self):
super().__post_init__() # 调用父类的 __post_init__
print("Child post-init")
# 使用示例
obj = Child(id=1, name="Alice")
# 输出:
# Base post-init
# Child post-init
特殊场景:修改 frozen
数据类
如果数据类被标记为 frozen=True
(不可变),直接修改字段会报错。此时需用 object.__setattr__
:
@dataclass(frozen=True)
class ImmutablePoint:
x: int
y: int
distance: float = field(init=False)
def __post_init__(self):
# 计算距离(因为类不可变,需特殊方式修改字段)
distance = (self.x ** 2 + self.y ** 2) ** 0.5
object.__setattr__(self, 'distance', distance)
# 使用示例
p = ImmutablePoint(3, 4)
print(p.distance) # 输出 5.0
__post_init__
在自动生成的__init__
方法之后调用。- 常用于数据验证、动态计算字段值或处理继承逻辑。
- 对
frozen=True
的类,需用object.__setattr__
修改字段。
(本文来源:nzw6.com)