## 适用版本与前置要求

  • `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`,可显著提升内存占用、构造安全与可维护性。


点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部