## 适用版本与前置要求
- `dataclasses` 标准库:Python 3.7+。
- `slots=True` 与 `kw_only=True`:Python 3.10+。
- `frozen=True`:Python 3.7+。
## 基础回顾:声明与字段
from dataclasses import dataclass, field, asdict, astuple, replace
from typing import List
@dataclass
class User:
id: int
name: str = "anonymous"
tags: List[str] = field(default_factory=list) # 避免可变默认值陷阱
u = User(id=1)
u.tags.append("vip")
print(asdict(u)) # {'id': 1, 'name': 'anonymous', 'tags': ['vip']}
print(astuple(u)) # (1, 'anonymous', ['vip'])
u2 = replace(u, name="alice")
print(u2)
要点:
- 使用 `field(default_factory=...)` 为可变字段创建独立实例,避免所有对象共享一个默认列表/字典。
- `asdict` 会对嵌套数据进行深拷贝(递归),在大对象上有开销;可按需使用 `astuple` 或自定义序列化。
## slots=True:减少内存并限制动态属性(Python 3.10+)
from dataclasses import dataclass
@dataclass(slots=True)
class Point:
x: float
y: float
p = Point(1.0, 2.0)
print(p.x, p.y)
# p.z = 3.0 # AttributeError:使用 slots 禁止添加未知属性
要点:
- `slots=True` 通过 `__slots__` 去掉 `__dict__`,减少内存与属性查找开销。
- 禁止动态添加新属性,提升数据结构的稳定性与可维护性。
## kw_only=True:强制关键字参数(Python 3.10+)
from dataclasses import dataclass
@dataclass(kw_only=True)
class Config:
host: str
port: int = 5432
ssl: bool = False
# c = Config("db.local", 5432) # TypeError:必须使用关键字参数
c = Config(host="db.local", port=5432, ssl=True)
print(c)
要点:
- `kw_only=True` 生成的 `__init__` 要求所有字段以关键字形式传递,避免参数位置错误与可读性问题。
## frozen=True:不可变对象与哈希(Python 3.7+)
from dataclasses import dataclass
@dataclass(frozen=True)
class Color:
r: int
g: int
b: int
red = Color(255, 0, 0)
print(hash(red))
# red.r = 0 # FrozenInstanceError:不可变
colors = {red: "primary"} # 可作为字典键
print(colors[red])
要点:
- `frozen=True` 使实例不可变,并根据字段生成可用的 `__hash__`(当字段皆可哈希时)。
- 不可变对象适合做缓存键、集合元素,提升语义与安全性。
## 比较与排序:eq 与 order
from dataclasses import dataclass
@dataclass(order=True)
class Item:
price: float
name: str
i1 = Item(9.9, "pen")
i2 = Item(5.0, "book")
print(i1 > i2) # True,按字段顺序比较(先 price,再 name)
要点:
- `eq=True`(默认)生成 `__eq__`;`order=True` 生成 `<, <=, >, >=`,按字段声明顺序比较。
- 若存在不参与比较的字段,使用 `field(compare=False)` 排除。
## 性能与工程实践
- 避免可变默认值:使用 `default_factory`,例如 `list/dict/set`。
- 大对象序列化:`asdict` 深拷贝成本高,数据量大时考虑自定义轻量序列化或只导出必要字段。
- 频繁创建的小对象:启用 `slots=True` 节省内存与属性访问时间。
- 明确构造语义:使用 `kw_only=True` 提升可读性并降低调用错误概率。
- 作为字典键或集合元素:启用 `frozen=True` 保证不可变与可哈希性。
## 组合示例:综合使用 slots、kw_only 与 frozen
from dataclasses import dataclass, field
from typing import Mapping
@dataclass(slots=True, kw_only=True, frozen=True)
class Endpoint:
url: str
headers: Mapping[str, str] = field(default_factory=dict)
api = Endpoint(url="https://example.com", headers={"Accept": "application/json"})
print(api)
# api.headers["X-Token"] = "abc" # 虽然 frozen,但内部可变对象仍可变;如需彻底不可变,使用不可变映射或元组
建议:
- 对内部集合也选择不可变类型(如 `types.MappingProxyType` 或 `tuple`)以保证真正不可变。
## 版本注意事项与验证
- `dataclasses` 在 3.7 引入;文中 `slots=True` 与 `kw_only=True` 仅在 Python 3.10+ 可用。
- 示例均为标准库,无第三方依赖;适用于 Windows/Linux/macOS。
## 结论
- 数据类为领域模型与轻量数据传输对象提供优雅语法。
- 合理使用 `slots`、`kw_only`、`frozen` 与 `default_factory`,可显著提升内存占用、构造安全与可维护性。

发表评论 取消回复