背景与目的

在 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)) # {'path': 'data/', 'secret': '12345'}
cfg2 = replace(cfg, path="new/")

优点总结

  • 属于标准库,零依赖;
  • 语法简洁、易读;
  • 性能好,类型提示友好;
  • 支持冻结、排序、默认工厂等。

attrs 模块详解

attrs 是一个更强大、更灵活的替代方案(功能超集),使用方式类似。

安装:

1
pip install 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)