1. 什么是 dataclasses? #

2. 为什么用 dataclass? #

对比 dataclass 普通类
代码量 少,自动生成方法 多,需手写
类型注解 强制,结构清晰 常被忽略
可变性 默认可变,可选 frozen 完全自定义

3. 快速上手 #

# 导入 dataclass 装饰器
from dataclasses import dataclass

# 声明为数据类,自动生成 __init__ 等方法
@dataclass
class Point:
    # 横坐标字段
    x: float
    # 纵坐标字段
    y: float

# 按字段顺序创建实例
p1 = Point(1.0, 2.0)
# 创建另一个相同坐标的实例
p2 = Point(1.0, 2.0)

# 自动生成的 __repr__ 输出
print(p1)
# 按字段值比较,相同坐标为 True
print(p1 == p2)

自动生成的方法:

方法 作用 默认
__init__ 构造实例 生成
__repr__ 打印展示 生成
__eq__ 等值比较 生成
__lt__ 等 排序比较 需 order=True
# 定义一个名为 Point 的类
class Point:
    # 构造方法,接收两个浮点数参数 x 和 y
    def __init__(self, x: float, y: float):
        # 将参数 x 赋值给实例变量 self.x
        self.x = x
        # 将参数 y 赋值给实例变量 self.y
        self.y = y
    # 定义对象的字符串表示方法
    def __repr__(self):
        # 返回格式化的字符串 "Point(x=..., y=...)"
        return f"Point(x={self.x}, y={self.y})"
    # 定义对象的相等性判断方法
    def __eq__(self, other):
        # 如果 other 不是 Point 类型,返回 False
        if not isinstance(other, Point):
            return False
        # 判断 x 和 y 是否都相等,相等则返回 True,否则返回 False
        return self.x == other.x and self.y == other.y

# 创建一个 Point 实例,坐标为 (1.0, 2.0)
p1 = Point(1.0, 2.0)
# 再创建一个 Point 实例,坐标也为 (1.0, 2.0)
p2 = Point(1.0, 2.0)
# 打印 p1 的字符串表示,会输出 Point(x=1.0, y=2.0)
print(p1)       # Point(x=1.0, y=2.0)
# 判断 p1 和 p2 是否相等,输出 True
print(p1 == p2) # True

4. 字段与默认值 #

# 导入 dataclass 和 field
from dataclasses import dataclass, field

# 声明数据类
@dataclass
class Person:
    # 必填字段:姓名
    name: str
    # 可选字段:默认年龄 20
    age: int = 20
    # 可变默认值必须用 default_factory,每实例独立列表
    tags: list[str] = field(default_factory=list)

# 错误写法:所有实例会共享同一个列表
# tags: list[str] = []

field() 常用参数:

参数 说明 示例
default 简单默认值 field(default=0)
default_factory 可变类型默认值 field(default_factory=list)
init=False 不参与构造参数 field(init=False)
repr=False 不显示在 print 中 field(repr=False)

5. post_init 与数据校验 #

# 导入 dataclass 和 field
from dataclasses import dataclass, field

# 声明数据类
@dataclass
class Person:
    # 必填字段:姓名
    name: str
    # 可选字段:默认年龄 20
    age: int = 20
    # 可变默认值必须用 default_factory,每实例独立列表
    tags: list[str] = field(default_factory=list)
    # 隐藏敏感字段,如密码(不会显示在 repr/print 中)
    password: str = field(default="", repr=False)
    # 由 __post_init__ 计算得出,不在 __init__ 参数中
    name_length: int = field(init=False)

    def __post_init__(self):
        # 通过 name 计算 name_length
        self.name_length = len(self.name)

# 错误写法:所有实例会共享同一个列表
# tags: list[str] = []

# 演示 field(init=False) 计算属性
p1 = Person("Tom", password="secret", tags=["hello"])
print(p1)  # password 不显示,name_length 自动生成

6. 转换与复制 #

# 导入 dataclass、asdict 和 replace
from dataclasses import dataclass, asdict, replace

# 二维坐标数据类
@dataclass
class Point:
    x: int
    y: int

# 创建实例
p = Point(1, 2)
# 转为字典,便于序列化
print(asdict(p))
# 创建修改 x 的新副本,原实例不变
p2 = replace(p, x=3)
print(p2)  # Point(x=3, y=2)

7. 高级特性 #

7.1 不可变实例(frozen) #

# frozen=True 使实例不可修改
@dataclass(frozen=True)
class ImmutablePoint:
    x: int
    y: int

# 创建不可变实例
p = ImmutablePoint(1, 2)
# 修改字段会抛出 FrozenInstanceError
# p.x = 3

7.2 排序支持(order) #

# order=True 自动生成比较方法
from dataclasses import field
from dataclasses import dataclass

@dataclass(order=True)
class Task:
    # 按 priority 排序
    priority: int
    # name 不参与比较
    name: str = field(compare=False)

# 按 priority 升序排列
print(sorted([Task(2, "B"), Task(1, "A")]))    

8. 实战示例 #

8.1 配置对象 #

# 导入 dataclass 装饰器
from dataclasses import dataclass

# 数据库连接配置,各字段有合理默认值
@dataclass
class DatabaseConfig:
    host: str = "localhost"
    port: int = 5432
    username: str = "admin"
    password: str = ""
    database: str = "app_db"

# 只覆盖需要修改的字段
config = DatabaseConfig(
    host="db.example.com",
    username="app_user",
    password="secret"
)
print(config)

8.2 API 响应封装 #

# 导入 dataclass 装饰器
from dataclasses import dataclass

# 统一 API 响应结构
@dataclass
class ApiResponse:
    success: bool
    data: dict
    message: str = ""
    code: int = 200

# 构造成功响应
resp = ApiResponse(
    success=True,
    data={"user_id": 123, "name": "Alice"},
    message="获取成功"
)
print(resp)

9. 常见错误 #

# 错误:可变默认值直接写 [],实例间共享
@dataclass
class Bad:
    items: list = []

# 正确:用 default_factory 为每实例创建独立列表
@dataclass
class Good:
    items: list = field(default_factory=list)

10. 总结 #

10.1 常用写法速查 #

# 导入常用 dataclass 工具
from dataclasses import dataclass, field, asdict, replace

# 用户数据类,含默认值和校验
@dataclass
class User:
    id: int
    name: str
    # 每实例独立的标签列表
    tags: list[str] = field(default_factory=list)
    # 令牌不显示、不参与构造
    _token: str = field(default="", repr=False, init=False)

    # 校验名称非空
    def __post_init__(self):
        if not self.name:
            raise ValueError("name 不能为空")

# 不可变配置类
@dataclass(frozen=True)
class Config:
    debug: bool = False
    timeout: int = 30

10.2 最佳实践 #