为何设置的Python递归限制未生效?递归深度超限问题排查
递归限制判断错误的原因及修正
你的代码触发RecursionError的核心问题是对sys.setrecursionlimit()的理解偏差,以及判断逻辑的疏漏:
1. 递归限制的实际含义
sys.setrecursionlimit(n)设置的是整个Python调用栈的最大层数,而非你计算的总调用次数。Python启动后,主程序(包括模块导入、顶层代码执行)已经占用了若干栈帧,所以实际可用于递归的栈层数会比n小。
比如你设置了100,但初始栈深度可能已经是3-4层,实际可用的递归深度只有96-97层左右。
2. 你的判断逻辑问题
你计算的-(len(ls) // -max_items)是处理列表所需的总调用次数(含初始调用),但递归深度是指从初始调用开始,每递归一次栈层数加1。比如处理970个元素需要97次调用,对应的递归深度是97层,加上初始栈的3层,总栈层数就会达到100,刚好触发递归限制。
修正后的代码
要准确判断是否会触发递归错误,需要结合当前的栈深度来计算剩余可用空间:
import sys sys.setrecursionlimit(100) max_items = 10 def foo(ls): # 计算处理列表所需的总调用次数(含当前调用) total_calls = -(len(ls) // -max_items) # 获取当前栈深度 current_depth = sys.getrecursiondepth() # 剩余可用于递归的栈层数 available_depth = sys.getrecursionlimit() - current_depth # 所需的递归次数是总调用次数减1(当前调用已占用一层) if (total_calls - 1) > available_depth: raise ValueError("List is too long. You'll hit the recursion limit") ls, ls_ = ls[:max_items], ls[max_items:] print(len(ls_)) if len(ls_) > 0: foo(ls_) foo(list(range(970)))
补充说明
sys.getrecursiondepth()(Python 3.10+可用)能准确获取当前调用栈的层数,避免了对初始栈深度的猜测。- 如果使用低于3.10的Python版本,可以通过
sys._getframe().f_depth来获取当前栈深度(注意sys._getframe()是私有API,谨慎使用)。
内容的提问来源于stack exchange,提问作者Alexander Soare
相关产品推荐
相关产品推荐

