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

为何Python递归限制因函数不同而存在差异?

Python递归限制为什么对不同函数表现不一样?

你的测试结果完全符合Python调用栈的工作机制——递归限制(sys.getrecursionlimit())管的是整个调用栈的总深度,不是单个函数的递归次数。不同函数触发RecursionError的深度差异,核心原因是异常处理块里的操作会占用额外栈帧,压缩了可递归的层数。

逐个拆解你的测试函数:

1. get_max_lvl() 返回998

这个函数的异常块只做了return lvl,几乎没有额外栈开销:

  • 默认递归限制是1000,初始调用get_max_lvl()已经占了1个栈帧。
  • 每递归一次新增1个帧,当递归到第998次时,栈里已有999个帧(初始帧+998次递归)。
  • 下一次调用get_max_lvl(999)会把栈深度推到1000,触发RecursionError,此时函数返回当前的lvl=998。

2. get_max_lvl_inspect() 返回981,栈层级显示983

这个函数的异常块调用了inspect.stack(),这是个栈开销极大的操作:

  • inspect.stack()会遍历当前所有栈帧生成列表,自身调用也会新增好几个栈帧。
  • 当递归到第981次时,栈深度已经逼近1000,下一次调用触发RecursionError。进入异常块后调用inspect.stack(),会额外占用栈空间——为了避免再次触发异常,Python会更早终止递归,所以实际递归层数比get_max_lvl()少很多。
  • 你看到的stack level:983是inspect.stack()返回的总帧数量,包含了它自身的调用帧、异常处理帧以及所有递归帧,所以实际递归层数(返回的lvl)比这个数小2。

3. get_max_lvl_other() 返回994,打印两次"blah"

这个函数的异常块调用了print(),print()会创建少量额外栈帧:

  • print()的栈开销远小于inspect.stack(),但仍会占用部分栈空间,所以递归层数比get_max_lvl()少,但比get_max_lvl_inspect()多。
  • 关于两次"blah":这是交互式环境的特性——当函数返回值时,Python会自动打印返回结果,print()和返回值的打印操作共用输出流,看起来像是两次输出;本质还是print()的栈开销导致递归层数被压缩。

研究方向参考:

  • Python栈帧结构:了解每个函数调用创建的FrameObject,以及调用栈的存储机制,栈深度就是这些对象的计数。
  • 异常处理的栈展开过程:当异常抛出时,Python会逐个销毁栈帧直到找到except块,而except块内调用函数会重新创建栈帧,这会影响栈深度的计算。
  • 递归限制的官方定义:sys.getrecursionlimit()限制的是解释器调用栈的最大深度,而非函数递归的次数,这点很容易混淆。
  • inspect模块的实现逻辑:inspect.stack()通过sys._getframe()遍历栈帧,这个过程本身会增加栈深度,是导致该函数递归层数骤降的关键。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 18:47:01