为何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
相关产品推荐
相关产品推荐

