“RecursionError” 的常见建议是 sys.setrecursionlimit,同时有人警告调大会让解释器崩溃。这篇用 Python 3.14.9 和 3.15.0 在本机验证:各种触发方式的报错原文、调大上限实际会怎样(内存还是崩溃)、C 代码里的深递归是另一道保护、线程栈有没有影响,以及哪些“修法”其实无效。
Python 3.14(退出码 0):
sys.getrecursionlimit() = 1000
到第 999 层时失败: RecursionError: maximum recursion depth exceeded
Python 3.15(退出码 0):
sys.getrecursionlimit() = 1000
到第 999 层时失败: RecursionError: maximum recursion depth exceeded
不捕获时的完整报错尾部(含被折叠的重复栈帧):
Python 3.15(退出码 1):
Traceback (most recent call last):
File "<tmp>/s3.py", line 2, in <module>
f()
~^^
File "<tmp>/s3.py", line 1, in f
def f(): f()
~^^
File "<tmp>/s3.py", line 1, in f
def f(): f()
…(共 15 行)1000,实际在第 999 层失败。
普通函数无限递归:
3.14: rc=1 RecursionError: maximum recursion depth exceeded
3.15: rc=1 RecursionError: maximum recursion depth exceeded
属性自己调用自己(@property 里读了自己):
3.14: rc=1 RecursionError: maximum recursion depth exceeded
3.15: rc=1 RecursionError: maximum recursion depth exceeded
__getattr__ 里读了没定义的属性:
3.14: rc=1 RecursionError: maximum recursion depth exceeded
3.15: rc=1 RecursionError: maximum recursion depth exceeded
__repr__ 里又 repr 自己:
3.14: rc=1 RecursionError: maximum recursion depth exceeded
3.15: rc=1 RecursionError: maximum recursion depth exceeded
json.loads 深嵌套数组:
3.14: rc=1 RecursionError: Stack overflow (used 16352 kB) while decoding a JSON array from a unicode string
3.15: rc=1 RecursionError: Stack overflow (used 16352 kB) while decoding a JSON array from a unicode string
深嵌套列表 repr:
3.14: rc=1 RecursionError: Stack overflow (used 16352 kB) while getting the repr of an object
3.15: rc=1 RecursionError: Stack overflow (used 16352 kB) while getting the repr of an object
copy.deepcopy 深嵌套:
3.14: rc=1 RecursionError: maximum recursion depth exceeded
3.15: rc=1 RecursionError: maximum recursion depth exceeded
比较两个深嵌套列表 ==:
3.14: rc=1 RecursionError: Stack overflow (used 16352 kB) in comparison
3.15: rc=1 RecursionError: Stack overflow (used 16352 kB) in comparison纯 Python 递归是 maximum recursion depth exceeded;经过 C 代码的是 Stack overflow (used … kB)。
Python 3.14,纯 Python 递归 100000 层(上限设 1000 万):退出码 0;纯 Python 递归 100000 层成功,结果 100000 | 峰值内存(ru_maxrss)约 28 MiB Python 3.14,纯 Python 递归 1000000 层(上限设 1000 万):退出码 0;纯 Python 递归 1000000 层成功,结果 1000000 | 峰值内存(ru_maxrss)约 166 MiB Python 3.14,纯 Python 递归 5000000 层(上限设 1000 万):退出码 0;纯 Python 递归 5000000 层成功,结果 5000000 | 峰值内存(ru_maxrss)约 607 MiB Python 3.15,纯 Python 递归 100000 层(上限设 1000 万):退出码 0;纯 Python 递归 100000 层成功,结果 100000 | 峰值内存(ru_maxrss)约 28 MiB Python 3.15,纯 Python 递归 1000000 层(上限设 1000 万):退出码 0;纯 Python 递归 1000000 层成功,结果 1000000 | 峰值内存(ru_maxrss)约 166 MiB Python 3.15,纯 Python 递归 5000000 层(上限设 1000 万):退出码 0;纯 Python 递归 5000000 层成功,结果 5000000 | 峰值内存(ru_maxrss)约 726 MiB Python 3.14,repr 嵌套 10000 层的列表(上限设 1000 万):退出码 0;repr 成功,长度 20002 Python 3.14,repr 嵌套 200000 层的列表(上限设 1000 万):退出码 0;RecursionError: Stack overflow (used 16352 kB) while getting the repr of an object Python 3.15,repr 嵌套 10000 层的列表(上限设 1000 万):退出码 0;repr 成功,长度 20002 Python 3.15,repr 嵌套 200000 层的列表(上限设 1000 万):退出码 0;RecursionError: Stack overflow (used 16352 kB) while getting the repr of an object
纯 Python 递归的代价是内存而不是崩溃;C 代码里的递归仍有独立的栈保护。
Python 3.14,threading.stack_size=默认:退出码 0;线程栈 默认 -> [50000] Python 3.14,threading.stack_size=262144:退出码 0;线程栈 262144 -> [50000] Python 3.14,threading.stack_size=67108864:退出码 0;线程栈 67108864 -> [50000] Python 3.15,threading.stack_size=默认:退出码 0;线程栈 默认 -> [50000] Python 3.15,threading.stack_size=262144:退出码 0;线程栈 262144 -> [50000] Python 3.15,threading.stack_size=67108864:退出码 0;线程栈 67108864 -> [50000]
纯 Python 递归不受线程栈大小影响。
Python 3.14:递归 -> RecursionError ; 迭代 -> 100000 ; 写成尾递归 -> RecursionError ; 递归 + lru_cache -> RecursionError Python 3.15:递归 -> RecursionError ; 迭代 -> 100000 ; 写成尾递归 -> RecursionError ; 递归 + lru_cache -> RecursionError
改成迭代;尾递归写法和 lru_cache 都无效。