dataclass列表字段不能直接写default=[],因为会导致所有实例共享同一可变对象;必须用default_factory=list或lambda: [...]来确保每个实例拥有独立列表。

dataclass列表字段为什么不能直接写default=[]
因为default=[]会让所有实例共享同一个可变对象,修改一个实例的列表,其他实例也会跟着变。这是Python中可变默认参数的经典陷阱,dataclass里照常生效。
必须用default_factory配list或lambda
正确做法是把default换成default_factory,并传一个可调用对象:
-
default_factory=list:最简洁,推荐用于空列表 -
default_factory=lambda: [1, 2, 3]:需要预设初始值时用 - 不能写
default_factory=[]——会报TypeError: mutable default <class> for field xxx is not allowed</class>
示例:
@dataclass
class Config:
tags: list[str] = field(default_factory=list)
extras: list[int] = field(default_factory=lambda: [0])
带类型提示的list字段要显式用field()
如果字段类型含泛型(如list[str]),且需要default_factory,就必须用field()包装,否则会报SyntaxError或类型检查器警告:
- ✅ 正确:
tags: list[str] = field(default_factory=list) - ❌ 错误:
tags: list[str] = field(default_factory=list())(括号执行了函数) - ❌ 错误:
tags: list[str] = [](可变默认值 + 缺少field())
初始化后修改列表字段不会影响其他实例
验证是否真正隔离,可以这样测:
a = Config()
b = Config()
a.tags.append("test")
print(b.tags) # 输出 [],不是 ["test"]
如果看到["test"],说明你没用default_factory,或者用了default=[]——这时候得回头检查field()调用和括号有没有多写。
泛型嵌套深、用到Optional[list]或Union时,default_factory的写法不变,但类型检查器可能更敏感;建议始终用field(default_factory=...)显式声明,别依赖隐式行为。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











