Python设置sys.setrecursionlimit后仍触发递归深度超限错误的原因排查
咱们先来梳理下你的问题:你明明把sys.setrecursionlimit设到了20000,但调用f(4952)这类大参数时还是触发了递归深度超限错误,错误提示里显示重复调用了996次后终止,最终结果预期是9200,你想不通为什么设置了更大的限制还是没用。
先看你提供的代码:
import sys from functools import * sys.setrecursionlimit(20000) @lru_cache(None) def f(n): if n <= 3: return n - 1 if n > 3: if n % 2 == 0: return f(n - 2) + (n / 2) - f(n - 4) else: return f(n - 1) * n + f(n - 2) result = f(4952) + 2 * f(4958) + f(4964) print(result)
触发的错误信息如下:
Traceback (most recent call last): File "-", line 21, in <module> result = f(4952) + 2 * f(4958) + f(4964) ^^^^^^^ File "-", line 14, in f return f(n - 2) + (n / 2) - f(n - 4) ^^^^^^^^ File "-", line 14, in f return f(n - 2) + (n / 2) - f(n - 4) ^^^^^^^^ File "-", line 14, in f return f(n - 2) + (n / 2) - f(n - 4) ^^^^^^^^ [Previous line repeated 996 more times] RecursionError: maximum recursion depth exceeded
原因分析
从错误里能看到,递归链只重复了996次就触发了错误,这个次数非常接近Python默认的1000层递归限制,说明你设置的20000很可能没真正生效,或者还有其他限制在起作用:
运行环境限制了递归深度的修改
有些在线IDE、沙箱环境会刻意限制sys.setrecursionlimit的修改,强制保留默认的递归深度来避免资源耗尽。你可以在设置后加一行代码验证:print(sys.getrecursionlimit()) # 看看实际输出是不是20000如果输出是1000,那说明你的设置被环境拦截了。
操作系统线程栈空间的隐性限制
就算sys.setrecursionlimit生效了,Python的递归调用还受操作系统分配给线程的栈空间大小限制。每个递归调用都会在栈里保存局部变量、返回地址等信息,当栈空间被耗尽时,哪怕解释器允许更大的深度,也会触发递归错误。对于n=4952,递归链长度是(4952-2)/2 = 2475层,理论上20000的限制足够,但如果环境给的栈空间太小,也会提前报错。递归逻辑的深度积累
虽然你用了lru_cache缓存结果,但第一次计算f(4952)时,必须从4952递归到2,这个完整的递归链是一次性执行的,中间的f(n-4)虽然会被缓存,但它的调用是在f(n-2)的递归栈完成之后,所以整个递归深度还是由最长的那条链决定。
解决方法
最稳妥的方式是把递归改成迭代,彻底绕开递归深度的问题,效率也更高:
def compute_f(max_n): f_cache = {} # 先处理基础情况 for n in range(1, 4): f_cache[n] = n - 1 # 从4开始向上计算到max_n for n in range(4, max_n + 1): if n % 2 == 0: f_cache[n] = f_cache[n-2] + (n / 2) - f_cache[n-4] else: f_cache[n] = f_cache[n-1] * n + f_cache[n-2] return f_cache # 计算到需要的最大值4964 f_cache = compute_f(4964) result = f_cache[4952] + 2 * f_cache[4958] + f_cache[4964] print(result)
这个代码从最小的n开始向上计算,用字典保存中间结果,完全没有递归调用,不管n多大都不会有深度问题,而且能直接得到预期的9200。
如果一定要用递归,可以先验证sys.setrecursionlimit是否生效,尝试设置更大的值(比如100000),但这种方法依赖环境,风险也更高。
备注:内容来源于stack exchange,提问作者lumba




