递归超限是cpython为防c栈溢出设的默认安全限制(约1000层),常见触发点包括深层json解析、mock的__repr__链式调用、property自引用、快排最坏情况;应优先改迭代而非盲目调高limit。

Python 报 RecursionError: maximum recursion depth exceeded 不是因为代码写错了,而是解释器主动踩了刹车——它默认只允许约 1000 层函数调用嵌套,防的是 C 栈被吃光导致崩溃。真要处理深层结构或写错终止条件,得知道怎么应对,而不是无脑加 limit。
为什么递归会超限,常见触发点在哪
CPython 用操作系统级的 C 栈管理函数调用,sys.getrecursionlimit() 返回的默认值(通常 1000)是安全余量,不是硬件极限。但真实爆栈常来自:
-
json.loads()解析 2000 层嵌套字典时直接撞上限,不是 JSON 错,是展开逻辑太深 - 测试中用了
mock.patch,断言失败触发__repr__→ 又打印 mock 对象 → 再次触发__repr__,隐式链式递归 -
@property里写return self.id,getter 调自己,无限套娃 - 快速排序最坏情况(已排序数组)递归深度退化成 O(n),万级数据轻松破千
改 sys.setrecursionlimit() 的风险和正确姿势
设成 10000 可能让你本地跑通,但在 CI 容器里被 kill -9 或直接 Segmentation fault。因为 OS 栈大小没变(Linux 默认 8MB),每层调用占 1–2KB,4MB 栈撑死 2000–3000 层。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
- 仅在明确输入深度可控时临时设:比如你知道树最多 1500 层,就设
sys.setrecursionlimit(2000) - 必须配
try/finally恢复原值,避免污染全局:先存old = sys.getrecursionlimit(),最后sys.setrecursionlimit(old) - 多线程下无效——每个线程栈独立,主线程设了 limit,子线程仍按默认跑;若需,得配合
threading.stack_size() - 别在递归函数内部设,要在触发前、最小作用域内设
绝大多数情况该直接改成迭代
递归只是思维模型,不是实现刚需。显式用 list 做栈,既绕过深度限制,又易加深度防护、超时和调试。
- 树 DFS:把
dfs(node.left); dfs(node.right)改成stack = [root],循环node = stack.pop(),再按需压入左右子节点 - 嵌套字典扁平化:不用
flatten(d)递归调自己,改用stack = list(d.items())+while stack: - 回溯路径:把局部变量
path提到循环外,用path.append()/path.pop()模拟入栈出栈 - 解析 JSON 或遍历结构时,加深度计数器:
if depth > 100: raise ValueError("too deep")
真正难的不是“怎么加 limit”,而是识别哪些递归本就不该存在——比如 @property 自我引用、mock 导致的隐式展开、或把分治逻辑硬写成线性递归。这些地方不重构,调 limit 只是给定时炸弹换块表皮。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










