default_factory必须是可调用对象而非调用结果,否则所有实例共享同一对象;正确写法为传函数名(如list)或lambda;default与default_factory不可共存;factory函数不接收参数且需线程安全。

field(default_factory) 必须是可调用对象,不能是调用结果
很多人写成 default_factory=list() 或 default_factory=datetime.now(),这会导致所有实例共享同一个默认值。Python 在类定义时就执行了括号里的调用,field 收到的是一个已创建的对象(比如空列表),而不是工厂函数本身。
正确做法是传函数名(不带括号)或 lambda:
from dataclasses import dataclass, field
from datetime import datetime
<p>@dataclass
class LogEntry:
tags: list = field(default_factory=list) # ✅ 正确:传函数名
created_at: datetime = field(default_factory=datetime.now) # ✅ 正确
metadata: dict = field(default_factory=lambda: {"version": "1.0"}) # ✅ 可用于带参数的场景
default_factory 和 default 不能同时指定
这是常见报错点:ValueError: cannot specify both default and default_factory。两者语义冲突——default 是固定值,default_factory 是每次新建实例时动态生成值的函数。
- 需要可变默认值(如
list,dict)→ 用default_factory - 需要不可变默认值(如
42,"unknown")→ 直接写default=... - 想让某个字段“无默认值但又允许不传”?不行,dataclass 要求所有非默认字段必须显式传参;此时应设为
Optional并配default_factory或default=None
自定义 factory 函数要注意作用域和参数
如果你写一个带参数的 factory,比如 default_factory=partial(dict, a=1),得确保它在类定义时能被访问到(不能是嵌套函数或局部变量)。更稳妥的是用 lambda 封装,或提前定义顶层函数。
立即学习“Python免费学习笔记(深入)”;
另外注意:factory 函数在每次实例化该字段时调用,**不接收任何参数**(dataclass 不会传入实例或上下文)。所以不要试图写 def make_id(obj): return obj.id + "_log" 这类依赖实例状态的逻辑——它不会生效。
示例错误写法:
@dataclass
class BadExample:
# ❌ 运行时报错:make_name() missing 1 required positional argument: 'obj'
name: str = field(default_factory=lambda obj: f"{obj.prefix}_log") # obj 不存在
使用 default_factory 时,字段自动变为可选,但类型提示仍需准确
即使用了 default_factory,dataclass 也不会自动帮你加 Optional[T]。如果字段本意可以为空(比如初始化后才赋值),而你又用了 default_factory=list,那类型仍是 list,不是 Optional[list]。这对 mypy 静态检查和 IDE 提示很重要。
建议显式标注(尤其当字段可能被重置为 None 时):
from typing import Optional, List from dataclasses import dataclass, field <p>@dataclass class Config: features: List[str] = field(default_factory=list) # 类型是 List[str] cache: Optional[dict] = field(default_factory=dict) # 类型是 Optional[dict]
真正容易被忽略的是:factory 函数本身是否线程安全、是否有副作用。比如用 default_factory=time.time 没问题,但若用 default_factory=write_log_to_file,就会在每次创建实例时悄悄写日志——而且无法控制时机。


















