背景与目的
在 Python 中,很多类只是用来存放数据的(例如配置、记录、实体对象),它们通常包含:
- 一堆属性或者字段
- 一个
__init__ 构造函数
- 一个
__repr__、__eq__、__hash__ 等方法
手写这些方法既冗长又容易出错,因此:
attrs 是一个第三方库(由 Hynek Schlawack 开发),最早解决了这个痛点;
dataclasses 是 Python 3.7 引入的标准库,受 attrs 启发,提供类似功能。
dataclasses 模块详解
基本用法
1 2 3 4 5 6
| from dataclasses import dataclass
@dataclass class Point: x: int y: int
|
等价于手写以下类:
1 2 3 4 5 6 7 8 9 10
| class Point: def __init__(self, x: int, y: int): self.x = x self.y = y
def __repr__(self): return f"Point(x={self.x}, y={self.y})"
def __eq__(self, other): return isinstance(other, Point) and self.x == other.x and self.y == other.y
|
常用参数
| 参数名 |
默认值 |
说明 |
init |
True |
是否自动生成 __init__ |
repr |
True |
是否生成 __repr__ |
eq |
True |
是否生成 __eq__ |
order |
False |
是否生成排序方法 (__lt__、__le__ 等) |
unsafe_hash |
False |
是否自动生成 __hash__(即使不可变) |
frozen |
False |
是否不可变(类似于 namedtuple) |
示例:
1 2 3 4
| @dataclass(order=True, frozen=True) class Person: name: str age: int
|
现在 Person 对象可比较、可哈希、不可修改。
默认值与工厂函数
普通默认值:
1 2 3 4
| @dataclass class User: name: str active: bool = True
|
若默认值为可变对象(如列表),必须使用 field(default_factory=...):
1 2 3 4 5
| from dataclasses import field
@dataclass class Group: members: list[str] = field(default_factory=list)
|
特殊字段控制
field() 用于精细控制字段的行为:
| 参数 |
功能 |
default / default_factory |
设置默认值或默认工厂 |
init |
是否出现在 __init__ 参数中 |
repr |
是否包含在 __repr__ 中 |
compare |
是否参与比较方法 (__eq__, __lt__) |
hash |
是否参与哈希计算 |
metadata |
附加元信息(任意字典) |
1 2 3 4
| @dataclass class Config: path: str secret: str = field(repr=False)
|
辅助函数
| 函数 |
作用 |
asdict(obj) |
转为字典 |
astuple(obj) |
转为元组 |
replace(obj, **changes) |
创建修改后的副本 |
fields(cls) |
返回字段定义列表 |
1 2 3 4 5
| from dataclasses import asdict, replace
cfg = Config("data/", "12345") print(asdict(cfg)) cfg2 = replace(cfg, path="new/")
|
优点总结
- 属于标准库,零依赖;
- 语法简洁、易读;
- 性能好,类型提示友好;
- 支持冻结、排序、默认工厂等。
attrs 模块详解
attrs 是一个更强大、更灵活的替代方案(功能超集),使用方式类似。
安装:
基本用法
1 2 3 4 5 6
| import attr
@attr.s class Point: x = attr.ib() y = attr.ib()
|
等价于:
1 2 3 4 5
| from dataclasses import dataclass @dataclass class Point: x: int y: int
|
参数控制
@attr.s() 和 attr.ib() 都可以控制行为:
1 2 3 4
| @attr.s(auto_attribs=True, frozen=True, order=True) class Person: name: str age: int = 0
|
| 参数 |
说明 |
auto_attribs |
支持类型注解 |
frozen |
不可变对象 |
order |
自动生成比较方法 |
kw_only |
仅允许关键字参数初始化 |
slots |
使用 __slots__ 优化内存 |
字段控制
attr.ib() 支持更多高级功能:
| 参数 |
说明 |
default |
默认值或工厂函数 |
validator |
字段验证函数 |
converter |
类型转换函数 |
repr, eq, order, hash |
同 dataclasses |
factory |
同 default_factory |
metadata |
任意元信息 |
示例:
1 2 3 4 5 6 7 8
| def is_positive(instance, attribute, value): if value <= 0: raise ValueError(f"{attribute.name} must be > 0")
@attr.s(auto_attribs=True) class Product: name: str price: float = attr.ib(validator=is_positive)
|
验证与转换
1 2 3
| @attr.s(auto_attribs=True) class Item: quantity: int = attr.ib(converter=int, validator=attr.validators.ge(1))
|
✅ 自动类型转换 + 校验。
attrs 内置验证器:
attr.validators.instance_of(type)
attr.validators.in_([...])
attr.validators.optional(...)
attr.validators.and_(), attr.validators.or_()
具函数
attr.asdict(), attr.astuple()
attr.evolve(obj, **changes) — 类似 dataclasses.replace
attr.fields(), attr.fields_dict()
attr.has(cls) — 是否为 attrs 类
对比总结
| 特性 |
dataclasses |
attrs |
| 所属 |
标准库 |
第三方库 |
| 语法 |
简洁 |
更灵活 |
| 验证器 |
❌ 无 |
✅ 有(强大) |
| 类型转换 |
❌ 无 |
✅ 有 |
| 关键字参数控制 |
✅ 有 (kw_only) |
✅ 有 |
| 性能 |
高 |
高(带 slots=True 更高) |
| 默认工厂 |
✅ |
✅ |
| 冻结 |
✅ |
✅ |
| 插件生态 |
少 |
丰富(attrs-strict, cattrs 等) |
实践建议
| 场景 |
推荐 |
| 标准库、通用项目 |
dataclasses |
| 需要验证、转换、灵活字段控制 |
attrs |
| 需要 JSON 序列化/反序列化 |
cattrs(配合 attrs 使用) |
| 性能敏感或内存受限 |
attrs(slots=True) |