给dataclass设置frozen=True后,普通字段赋值会被拒绝,但字段引用的列表仍可能改变。要表达真正稳定的数据快照,需要同时检查字段里的对象,而不只看装饰器上的frozen选项。

把重新赋值与修改已有对象分开
record.tags = […]试图替换字段;record.tags.append(…)则是在原列表上执行操作。frozen生成的赋值限制针对前一种常见路径,不会递归地把列表转换成不可变结构。
from dataclasses import dataclass, field, FrozenInstanceError
@dataclass(frozen=True)
class Record:
title: str
tags: list[str] = field(default_factory=list)
item = Record("note")
try:
item.title = "changed"
except FrozenInstanceError:
pass
else:
raise AssertionError("field assignment should fail")
item.tags.append("python")
assert item.tags == ["python"]
try:
hash(item)
except TypeError:
pass
else:
raise AssertionError("list field is unhashable")
print(item)
能创建对象,也不一定能当字典键
默认eq与frozen组合可以让dataclass生成哈希方法,但字段里的list本身不可哈希,因此本例调用hash时仍报TypeError。不要因为类定义成功或看到frozen,就认定任何实例都可以放入set。代码已在本地验证这两个不同失败点。
需要快照时,从数据结构设计开始
如果tags只是不可变文字标签,使用tuple[str, …]通常更贴近这个意图;但tuple里若又包着list,也并非深层不可变。应沿着实际字段逐层检查,并在外部可变输入进入对象时明确转换或复制规则。类型注解本身不会替你自动转换传入值。
它不是权限或安全隔离边界
frozen适合表达程序中的只读约定、减少意外赋值,不用来阻止不受信任代码修改内存。评价一个对象是否能安全共享,应看实际内容、调用方式和信任边界。本文没有为了演示去绕过冻结限制,正常append行为已足以说明差别。
资料来源与继续学习
资料查阅日期:2026年10月14日。示例、阅读练习与操作建议由本站整理。
资料查阅与编辑日期:2026年10月14日。作者:玖柒。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END






