pytest触发recursionerror的根本原因是测试或被测代码中存在隐式递归(如自引用对象、错误__repr__、循环fixture依赖等),pytest在收集、断言、格式化或异常处理时深度遍历对象而直接崩溃。

pytest 崩溃时抛出 RecursionError: maximum recursion depth exceeded,根本原因几乎总是测试代码或被测代码中存在隐式递归调用,而非 pytest 本身限制过低。
为什么 pytest 会触发 RecursionError?
pytest 在收集测试、执行断言、格式化失败信息(尤其是对嵌套数据结构调用 repr())、处理异常链(__cause__/__context__)时,会深度遍历对象。若被测对象(如自引用字典、循环链表、重载了 __getattr__ 的代理类)或测试辅助函数(如递归 mock、错误的 fixture 依赖)形成隐式递归,pytest 就会在这些环节直接崩溃。
- 常见诱因:
__repr__或__str__方法意外调用自身(例如误写成return str(self)) - mock 对象配置不当:用
side_effect指向一个会再次调用被 mock 函数的函数 - fixture 之间形成循环依赖(A fixture 依赖 B,B 又在 setup 阶段间接依赖 A)
- 自定义断言函数或 pytest 插件未处理循环引用
快速定位递归源头的方法
不要先改 sys.setrecursionlimit() —— 这只是掩盖问题,且可能引发栈溢出崩溃。优先用 Python 自带工具抓现场:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 运行测试时加
-s参数(禁用输出捕获),让原始 traceback 显示出来;重点看最后一段重复出现的函数名 - 在报错前插入
import traceback; traceback.print_stack()到可疑 fixture 或setup_method中,观察调用链 - 临时在项目根目录下加一个
conftest.py,注入全局钩子:import sys def pytest_runtest_makereport(item, call): if call.excinfo and "RecursionError" in str(call.excinfo.exconly()): print("Recursion detected in:", item.name) sys.settrace(None) # 防止 trace 干扰
修复策略:从代码层切断递归链
核心原则是让对象可安全 repr、可被 pytest 序列化、不触发意外调用。不是增加栈空间,而是消除循环。
- 检查所有自定义类的
__repr__:确保不调用self.__dict__中可能含 self 的字段;改用vars(self).keys()或显式白名单字段 - 避免在
__getattr__中无条件 fallback 到self.some_attr;加守卫判断属性名是否已处理过 - mock 时慎用
side_effect回调函数;优先用return_value,或确保回调函数不重新进入被测逻辑 - 对深度嵌套/循环引用的数据结构,在断言前用
copy.deepcopy()或json.loads(json.dumps(...))做一次“净化”,再传给assert
什么时候才该调高 recursion limit?
仅当确认是合法的、可控的深度递归(比如解析超深嵌套 JSON、测试一个明确设计为递归 N 层的算法),且已排除所有隐式递归后,才考虑临时调整:
- 在具体测试函数开头加:
import sys original_limit = sys.getrecursionlimit() sys.setrecursionlimit(3000) try: # your test code finally: sys.setrecursionlimit(original_limit) - 绝对不要在
conftest.py全局设置;pytest 收集阶段就可能触发,此时还没进测试函数 - 值设太高(如 >10000)反而易导致 C-level 栈溢出,进程直接 killed
真正棘手的是那些只在特定 fixture 组合或参数化场景下才暴露的隐式递归——它往往不报错,而是让 pytest 卡死或静默退出。遇到这种情况,逐个注释 fixture、用 --tb=short 缩小 traceback 范围,比盲目调参更可靠。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










