You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python dataclasses default_factory定义list属性触发RecursionError

问题诱因

该递归错误是Python 3.10及更早版本中,dataclass处理类体内自引用类型注解的已知运行时bug,和类中定义的classmethod自定义构造函数无关,核心触发逻辑如下:

  • 类定义阶段的求值顺序问题:在MyDataClass类体中编写list[MyDataClass]作为属性类型标注时,MyDataClass类对象尚未完成创建——dataclass装饰器的处理逻辑在类体代码执行完毕后立刻运行,此时类处于半初始化状态。如果未开启注解延迟求值,Python会立刻对list[MyDataClass]这个注解表达式求值,最终拿到绑定了半初始化类的泛型类型对象。
  • 递归触发逻辑:dataclass处理类时会调用inspect.signature生成构造函数签名,签名格式化流程会尝试将每个参数的类型注解转为字符串,转换过程中会触发dataclass的Field对象的__repr__方法。由于自引用泛型注解持有半初始化类的引用,类的属性字典中又持有对应的Field对象,__repr__遍历属性时会再次命中同一个Field对象,形成逻辑上的无限递归,最终抛出RecursionError,这种场景下手动调高递归上限没有任何作用。

两个特殊现象的原因:

  • PyCharm调试时不触发错误:PyCharm调试运行时默认会注入补丁,将所有类型注解以字符串形式延迟处理,不会在类定义阶段立刻求值list[MyDataClass],因此不会触发递归。
  • 属性初始化为None时不报错:将属性默认值设为None时,dataclass处理字段的逻辑不会提前触发泛型参数的递归解析,因此不会踩中该bug。
修复方案

按推荐优先级排序:

  • 零侵入最优方案:在文件最开头、所有import语句之前添加一行from __future__ import annotations。该语句是Python官方提供的注解延迟求值特性,会将文件内所有类型注解以字符串形式存储,不会在类定义阶段立刻求值,从根源上规避自引用注解的求值时机问题。Python 3.11及以上版本该特性已作为默认行为开启。
  • 单字段适配方案:将自引用的类型注解改写为字符串字面量形式,即把属性定义从children: list[MyDataClass] = field(default_factory=list)修改为children: "list[MyDataClass]" = field(default_factory=list),效果与上述future导入一致,仅需对存在自引用的字段单独修改。
  • 版本升级方案:直接将运行环境的Python版本升级到3.11及以上,官方已在该版本修复dataclass处理自引用泛型注解时的递归bug,无需额外修改业务代码。

内容的提问来源于stack exchange,提问作者keylongx3x0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 20:15:51