json.loads()和pprint.pprint()触发recursionerror是因为深度嵌套或循环引用超出python默认1000层递归限制,本质是调用栈过深而非内存或格式问题;应改用迭代+深度控制+循环检测来安全处理。

为什么json.loads()和pprint.pprint()会触发RecursionError?
Python默认递归限制是1000层,而深度嵌套的字典/列表(比如解析某些API返回的树形结构、自引用JSON、或意外生成的循环引用)会迅速突破这个阈值。典型报错是RecursionError: maximum recursion depth exceeded,不是数据太大,而是调用栈太深。
关键点在于:这不是内存不足问题,不能靠增加RAM解决;也不是JSON格式错误,json.loads()可能已成功解析,但后续打印或遍历时崩溃。
-
pprint.pprint()默认递归展开所有层级,遇到500+层嵌套就大概率失败 -
json.dumps()在序列化含循环引用的对象时也会递归卡死(即使用了default参数) - 手动写的递归遍历函数若没设深度计数器,同样踩坑
用sys.setrecursionlimit()是否安全?
能临时绕过错误,但不推荐作为常规解法。提高限制值(如设为3000)可能让程序在栈溢出时直接崩溃,而非抛出可捕获的RecursionError,尤其在C扩展或嵌入式环境中风险更高。
更稳妥的做法是改写逻辑,避开深层递归:
- 用显式栈(
list)替代函数调用栈,例如DFS遍历时用stack = [(root, 0)]记录节点和当前深度 - 对
pprint加限制:pprint.pprint(data, depth=5, width=80),depth参数能强制截断嵌套 - 检查数据是否含循环引用——用
id()缓存已访问对象,发现重复id立即终止遍历
如何安全地遍历并处理嵌套结构?
核心原则:把“递归”转为“迭代”,并始终监控深度与对象唯一性。
示例:一个带深度保护和循环检测的扁平化函数:
def safe_flatten(obj, max_depth=100, seen=None):
if seen is None:
seen = set()
if id(obj) in seen:
return "[circular ref]"
if max_depth <p>注意<code>seen.discard(id(obj))</code>必须在递归返回前清理,否则影响同一对象在其他分支的判断。</p><h3>处理JSON循环引用的特殊场景</h3><p>标准<code>json</code>模块不支持循环引用,但有些第三方库(如<code>jsonpickle</code>)会注入<code>$ref</code>字段。若你必须处理这类数据:</p>
- 先用
json.loads()加载原始字符串,再用safe_flatten()类函数处理结果 - 避免用
json.dumps(obj, default=str)——str()对嵌套对象仍会触发递归 - 真正需要序列化的场景,改用
orjson或ujson,它们对深度控制更严格,且报错更早、更明确
最常被忽略的是:很多所谓“大嵌套”其实是意外的无限递归(比如父节点存了子节点引用,子节点又反向引用父节点),这种必须靠id()检测,光调高递归限制只会让崩溃更晚、更难定位。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











