← 返回题目列表

Python 的递归深度限制是什么?为什么 Python 不做尾递归优化?

中等 第 21 / 21 题 更新于 2026/07/31
Python递归递归深度尾递归

简化版

**Python 默认限制递归深度约 1000 层(sys.getrecursionlimit()),超过就抛 RecursionError: maximum recursion depth exceeded,防止无限递归把「调用栈」撑爆导致解释器崩溃。**关键点:① 为什么有限制——每次函数调用会在调用栈上压一个「栈帧」(保存局部变量、返回地址),递归太深会耗尽栈空间;Python 用一个「软限制」(默认 1000)在真正崩溃前主动抛异常(比 C 栈溢出崩溃更友好);② 可以调整——sys.setrecursionlimit(n) 能改,但调太大有真的栈溢出崩溃风险(Python 层限制之外还有 C 栈的物理限制);③ Python 不做尾递归优化(TCO)——即使写成尾递归形式,Python 也不会把它优化成循环,Guido 明确拒绝(理由:会破坏「完整的调用栈回溯」、递归不是 Python 推荐的循环方式)。结论:Python 里深递归应改写成「迭代(循环)」或用「显式栈」,别指望尾递归优化。例子:深度遍历、阶乘、斐波那契用循环或记忆化更好。核心记忆:递归深度默认约 1000(可 setrecursionlimit 调但有栈溢出风险),Python 不做尾递归优化(Guido 拒绝),深递归改写成迭代/显式栈。

详细版

递归深度限制

方面说明
默认限制约 1000(sys.getrecursionlimit()
超限RecursionError
调整sys.setrecursionlimit(n)(有栈溢出风险)
尾递归优化Python 不做(Guido 拒绝)
深递归的解法改写成迭代 / 显式栈
import sys

# 查看和设置递归限制
print(sys.getrecursionlimit())    # 1000(默认)

# 无限递归会触发 RecursionError(而非崩溃)
def bad(n):
    return bad(n + 1)
# bad(0)   # RecursionError: maximum recursion depth exceeded

# 深递归超限例子
def depth(n):
    if n == 0: return 0
    return depth(n - 1) + 1
# depth(2000)   # RecursionError(超过 1000)

# 调整限制(谨慎!可能真的栈溢出崩溃)
sys.setrecursionlimit(3000)
print(depth(2000))    # 现在能跑(但风险自负)
sys.setrecursionlimit(1000)   # 改回

# Python 不优化尾递归——写成尾递归也一样会超限
def fact_tail(n, acc=1):
    if n == 0: return acc
    return fact_tail(n - 1, acc * n)   # 尾调用,但 Python 不优化
# fact_tail(2000)   # 仍然 RecursionError!

# 正确做法:改写成迭代(循环)
def fact_iter(n):
    acc = 1
    for i in range(1, n + 1):
        acc *= i
    return acc
print(fact_iter(2000))    # ✓ 无深度限制,能算超大阶乘

# 深度优先遍历:递归 → 显式栈
def dfs_iter(root):
    stack = [root]
    while stack:
        node = stack.pop()
        # 处理 node
        stack.extend(node.children)   # 用列表当栈,不受递归限制

⚠️ 两个核心认知:① Python 限制递归深度(默认 ~1000)是一种「保护」——每层递归在调用栈上占一个栈帧,太深会耗尽内存/栈空间,Python 在真正崩溃前主动抛 RecursionError(比 C 那种直接段错误崩溃友好);② Python 故意不做「尾递归优化」,所以在 Python 里递归不是深层循环的好工具,深递归要改成迭代。很多人从函数式语言(Scheme、Haskell)带来「尾递归 = 循环」的直觉,在这些语言里尾递归会被优化成不增长栈的循环;但 Guido 明确拒绝在 Python 里加 TCO,理由很实际:① 会破坏「完整的栈回溯(traceback)」——调试时看不到完整调用链;② Python 的哲学是「显式循环优于递归」,不想鼓励用递归模拟循环;③ 实现复杂、收益不大。所以在 Python 里:能用循环就用循环(阶乘、求和、遍历);天然递归的问题(树/图遍历、分治)如果深度可能很大,改成「显式栈 + while 循环」(把递归的隐式调用栈换成自己管理的列表);sys.setrecursionlimit 可以调高但要小心——它只是抬高 Python 的软限制,底层 C 栈仍有物理上限,调太高会真的段错误崩溃。

完整版教学

一、递归与调用栈

先理解递归为什么会有深度问题:

递归:函数调用自己
  def f(n):
      if n == 0: return 0    # 基线条件(base case)
      return f(n-1) + 1      # 递归调用

每次函数调用 → 压一个"栈帧"到调用栈:
  栈帧保存:局部变量、参数、返回地址(调用完回哪)
  f(3) 调 f(2) 调 f(1) 调 f(0)
  → 栈上同时有 4 个栈帧(f0,f1,f2,f3 都还没返回)

调用栈(call stack):
  [f(3)]  ← 最先调用
  [f(2)]
  [f(1)]
  [f(0)]  ← 最后调用(栈顶)
  → f(0) 返回后逐层弹出、回填结果

深度问题:
  递归越深 → 栈帧越多 → 占用栈空间越大
  无限递归 / 太深 → 栈空间耗尽 → 崩溃

栈空间有限:
  程序的调用栈大小有限(几 MB)
  每个栈帧占若干字节
  → 太多栈帧会溢出(stack overflow)

对比迭代(循环):
  循环不压新栈帧,只有一个栈帧、复用变量
  → 无深度限制(只受数据量限制)

所以递归每层压一个栈帧,栈空间有限,太深会溢出;迭代不压栈帧无深度限制

递归:函数调用自己(要有基线条件 base case 终止)。每次函数调用压一个「栈帧」到调用栈:栈帧保存局部变量、参数、返回地址。f(3)→f(2)→f(1)→f(0) 时栈上同时有 4 个栈帧(都没返回)。调用栈:后调用的在栈顶、f(0) 返回后逐层弹出回填结果。深度问题:递归越深栈帧越多、占用栈空间越大、无限/太深会耗尽栈空间崩溃。栈空间有限:程序调用栈几 MB、每个栈帧占若干字节、太多会溢出(stack overflow)。对比迭代(循环):循环不压新栈帧、只有一个栈帧复用变量、无深度限制(只受数据量限制)。理解「递归每层压一个栈帧(存局部变量/参数/返回地址),栈空间有限(几 MB),太深会栈溢出;迭代不压栈帧、只一个栈帧复用、无深度限制」,就理解了递归的深度问题。

二、Python 的递归深度限制

理解 Python 的软限制机制:

Python 的递归深度限制:
  sys.getrecursionlimit()  → 1000(默认)
  → 递归深度超过约 1000 层,抛 RecursionError

为什么设"软限制"(Python 层面主动检查):
  ① C 栈溢出会导致解释器"段错误崩溃"(无法恢复、无堆栈信息)
  ② Python 在每次函数调用时检查深度,超限就抛 Python 异常
     → 可被 try/except 捕获、有清晰的错误信息
     → 比直接崩溃友好得多

RecursionError 信息:
  RecursionError: maximum recursion depth exceeded
  → 告诉你递归太深(可能是忘了基线条件的无限递归)

限制不完全等于 1000 层用户函数:
  限制是"C 栈的帧数",包括解释器内部调用
  → 实际用户递归可能到不了 1000(内部调用也占)

调整限制:
  sys.setrecursionlimit(n)
  → 抬高软限制(但 C 栈物理上限还在)
  → 调太高:软限制过了、C 栈爆了 → 真的段错误崩溃
  → 一般不建议大幅调高(说明该改迭代了)

查看当前深度:
  len(inspect.stack())   # 当前调用栈深度

所以 Python 软限制默认 1000(超抛 RecursionError),比 C 栈崩溃友好,可调但有风险

Python 的递归深度限制sys.getrecursionlimit() → 1000(默认),超过约 1000 层抛 RecursionError为什么设「软限制」(Python 层面主动检查)① C 栈溢出会导致解释器段错误崩溃(无法恢复、无堆栈信息)、② Python 每次函数调用检查深度、超限抛 Python 异常(可被 try/except 捕获、有清晰错误信息、比崩溃友好)RecursionError 信息maximum recursion depth exceeded(可能是忘了基线条件的无限递归)。限制不完全等于 1000 层用户函数:限制是「C 栈的帧数」(包括解释器内部调用、实际用户递归可能到不了 1000)。调整限制sys.setrecursionlimit(n) 抬高软限制(但 C 栈物理上限还在、调太高会真的段错误崩溃、一般不建议大幅调高——说明该改迭代了)。理解「Python 软限制默认 1000(超抛 RecursionError),软限制在真正崩溃前主动抛异常比 C 栈段错误友好;限制含内部调用;setrecursionlimit 可调但 C 栈物理上限还在、调太高真崩溃」,就掌握了递归深度限制。

三、Python 不做尾递归优化

理解为什么 Python 没有 TCO:

尾递归(tail recursion):
  递归调用是函数的"最后一个动作"(返回值就是递归调用的结果)
  def fact(n, acc=1):
      if n == 0: return acc
      return fact(n-1, acc*n)   # 尾调用(最后就是递归,无额外计算)

尾递归优化(TCO, Tail Call Optimization):
  有些语言(Scheme、Haskell、部分 JS 引擎)会优化:
  尾递归时"复用当前栈帧"(不压新帧)
  → 尾递归变成"循环",不增长栈、无深度限制

Python 不做 TCO:
  即使写成尾递归,Python 也照常压栈帧
  → fact(2000) 仍然 RecursionError(不会被优化)

Guido 明确拒绝 TCO(理由):
  ① 破坏栈回溯(traceback)——优化后调试看不到完整调用链
     Python 重视清晰的错误堆栈
  ② 哲学:显式循环优于递归——不想鼓励用递归模拟循环
     "Python 不是函数式语言,别把递归当循环用"
  ③ 实现代价 vs 收益——加 TCO 复杂、收益有限
  ④ 隐式优化违反"显式优于隐式"

结论:
  在 Python 里"尾递归 = 循环"的直觉不成立
  → 尾递归和普通递归一样受深度限制
  → 深递归必须手动改成迭代

对比其他语言:
  Scheme: 尾递归 = 循环(语言规范要求 TCO)
  Python: 尾递归 = 普通递归(无优化)
  → 从函数式语言转来要调整思维

所以 Python 不做尾递归优化(Guido 拒绝:破坏栈回溯+显式循环优于递归),尾递归也受限

尾递归(tail recursion):递归调用是函数的「最后一个动作」(返回值就是递归调用的结果,return fact(n-1, acc*n) 无额外计算)。尾递归优化(TCO):有些语言(Scheme、Haskell、部分 JS 引擎)会优化——尾递归时复用当前栈帧(不压新帧),尾递归变成循环(不增长栈、无深度限制)。Python 不做 TCO:即使写成尾递归也照常压栈帧(fact(2000) 仍 RecursionError)。Guido 明确拒绝 TCO(理由)① 破坏栈回溯(优化后调试看不到完整调用链)、② 哲学(显式循环优于递归、Python 不是函数式语言)、③ 实现代价 vs 收益、④ 隐式优化违反「显式优于隐式」。结论:Python 里「尾递归 = 循环」的直觉不成立、深递归必须手动改成迭代。理解「Python 不做尾递归优化(TCO);尾递归调用是最后动作、有的语言会复用栈帧变循环、Python 不会;Guido 拒绝:破坏栈回溯+显式循环优于递归+代价大;尾递归也受深度限制、必须手动改迭代」,就掌握了为什么 Python 没有 TCO。

四、深递归的正确改写

理解怎么把深递归改成迭代:

深递归的改写方案:

方案1:线性递归 → 循环(最简单)
  # 递归阶乘(受深度限制)
  def fact(n):
      if n == 0: return 1
      return n * fact(n-1)
  # 改成循环(无深度限制)
  def fact(n):
      acc = 1
      for i in range(1, n+1): acc *= i
      return acc

方案2:树/图递归 → 显式栈 + 循环
  # 递归 DFS(深树会超限)
  def dfs(node):
      visit(node)
      for c in node.children: dfs(c)
  # 改成显式栈
  def dfs(root):
      stack = [root]
      while stack:
          node = stack.pop()
          visit(node)
          stack.extend(reversed(node.children))  # 用列表当栈
  → 把"递归的隐式调用栈"换成"自己管理的列表"
  → 不受递归深度限制(只受内存限制)

方案3:记忆化(减少递归次数,但不减深度)
  # 斐波那契:记忆化避免重复计算(但深度仍在)
  from functools import lru_cache
  @lru_cache
  def fib(n):
      if n < 2: return n
      return fib(n-1) + fib(n-2)
  → 记忆化解决"指数爆炸",但深度问题要靠迭代

方案4:确实需要深递归 → 调高限制(谨慎)
  sys.setrecursionlimit(10000)  # 风险自负(可能真崩溃)

选择:
  线性递归 → 循环
  树/图/分治 → 显式栈(栈/队列)+ 循环
  重复子问题 → 记忆化 + 迭代
  实在要深递归 → 调限制(但优先改迭代)

所以改写:线性递归→循环、树图→显式栈+循环、重复→记忆化;别轻易调限制

深递归的改写方案方案1:线性递归 → 循环(最简单)(阶乘、求和改成 for 循环、无深度限制);方案2:树/图递归 → 显式栈 + 循环(递归 DFS 改成 stack = [root]; while stack: node = stack.pop(); stack.extend(...),把递归的隐式调用栈换成自己管理的列表、不受递归深度限制);方案3:记忆化(减少递归次数,但不减深度)(斐波那契用 @lru_cache 避免重复计算、但深度问题要靠迭代);方案4:确实需要深递归 → 调高限制(谨慎)sys.setrecursionlimit(10000) 风险自负)。选择:线性递归用循环、树/图/分治用显式栈、重复子问题用记忆化+迭代、实在要深递归调限制(但优先改迭代)。理解「改写:①线性递归→循环②树图递归→显式栈+while(把隐式调用栈换成自己的列表)③记忆化 lru_cache 减少次数但不减深度④调 setrecursionlimit(谨慎);优先改迭代别轻易调限制」,就掌握了深递归改写。

五、递归的适用与陷阱

理解递归什么时候合适、有什么坑:

递归适合的场景(Python 里):
  ① 天然递归结构,且深度可控(< 1000):
     树遍历(不太深)、分治(归并/快排)、回溯
  ② 表达清晰胜过性能:
     递归写法更接近问题本质(如汉诺塔)
  → 深度可控时递归代码更简洁易懂

递归的陷阱:
  ① 忘了基线条件 → 无限递归 → RecursionError
     def f(n): return f(n-1)   # 永远不停
  ② 深度可能很大 → 超限(图算法、深树、大 n)
  ③ 重复计算 → 指数爆炸(朴素斐波那契 O(2^n))
     → 记忆化解决
  ④ 每层栈帧开销 → 递归比迭代慢、占内存

Python 递归慢的原因:
  函数调用开销大(压栈、传参、Python 解释开销)
  → 同样逻辑,迭代通常比递归快

性能对比(概念):
  fact 递归 vs 迭代:迭代快(无函数调用开销)
  DFS 递归 vs 显式栈:显式栈无深度限制、通常也更快

实践建议:
  ① 深度可控 + 天然递归 → 递归(简洁)
  ② 深度可能大 → 迭代/显式栈
  ③ 重复子问题 → 记忆化
  ④ 性能敏感的深循环 → 迭代

所以递归适合深度可控的天然递归结构;陷阱:无限递归/超限/重复计算/慢

递归适合的场景(Python 里)① 天然递归结构且深度可控(< 1000)(树遍历、分治归并/快排、回溯)、② 表达清晰胜过性能(递归更接近问题本质、如汉诺塔)。递归的陷阱① 忘了基线条件 → 无限递归 → RecursionError、② 深度可能很大 → 超限、③ 重复计算 → 指数爆炸(朴素斐波那契 O(2^n)、记忆化解决)、④ 每层栈帧开销 → 递归比迭代慢/占内存Python 递归慢的原因:函数调用开销大(压栈、传参、解释开销)、同样逻辑迭代通常更快。实践建议:深度可控+天然递归用递归、深度可能大用迭代/显式栈、重复子问题用记忆化、性能敏感用迭代。理解「递归适合深度可控的天然递归结构(树/分治/回溯);陷阱:忘基线条件→无限递归、深度大→超限、重复计算→指数爆炸(记忆化解)、栈帧开销→慢;深度可控用递归、深度大用迭代」,就掌握了递归的适用与陷阱。

六、总结与实践

总结递归限制:

核心:
  Python 默认递归深度约 1000(sys.getrecursionlimit)
  超过抛 RecursionError(软限制,比 C 栈崩溃友好)
  Python 不做尾递归优化(Guido 拒绝)

为什么有限制:
  每层递归压一个栈帧,栈空间有限,太深会溢出
  软限制在真正崩溃前主动抛异常

为什么不做 TCO:
  破坏栈回溯 + 显式循环优于递归(Python 哲学)

深递归的解法:
  线性递归 → 循环
  树/图/分治 → 显式栈 + while
  重复子问题 → 记忆化(lru_cache)+ 迭代
  实在要深递归 → setrecursionlimit(谨慎,有真崩溃风险)

调整限制的风险:
  setrecursionlimit 只抬软限制,C 栈物理上限还在
  → 调太高会真的段错误崩溃

实践建议:
  ① 深度可控 + 天然递归 → 递归(简洁)
  ② 深度可能大 → 迭代/显式栈(无限制、更快)
  ③ 别指望尾递归优化

核心总结:
  递归深度默认 ~1000(可调有风险)
  Python 不做尾递归优化
  深递归改迭代/显式栈

所以递归深度默认 1000、不做尾递归优化,深递归改迭代/显式栈

核心:Python 默认递归深度约 1000(sys.getrecursionlimit)、超过抛 RecursionError(软限制、比 C 栈崩溃友好)、不做尾递归优化。为什么有限制:每层递归压栈帧、栈空间有限、软限制在崩溃前主动抛异常。为什么不做 TCO:破坏栈回溯 + 显式循环优于递归。深递归的解法:线性递归→循环、树/图/分治→显式栈+while、重复子问题→记忆化+迭代、实在要深递归→setrecursionlimit(谨慎)。调整限制的风险:只抬软限制、C 栈物理上限还在、调太高真崩溃。理解「递归深度默认 1000(超抛 RecursionError、软限制友好)、不做尾递归优化(Guido 拒绝);深递归改迭代/显式栈/记忆化;setrecursionlimit 调太高真崩溃」,就掌握了总结与实践。

记忆钩子:「Python 默认限制递归深度约 1000(sys.getrecursionlimit()),超过抛 RecursionError:maximum recursion depth exceeded;★为什么有限制:每次函数调用在调用栈压一个『栈帧』(存局部变量/参数/返回地址),递归太深耗尽栈空间,Python 用『软限制』在真正崩溃前主动抛 Python 异常(可 try/except、有清晰堆栈,比 C 栈段错误崩溃友好得多);★Python 故意不做『尾递归优化(TCO)』——即使写成尾递归(return f(n-1,acc*n)递归是最后动作),Python 也照常压栈帧、仍会超限,Guido 明确拒绝,理由:①破坏完整栈回溯 traceback(调试看不到调用链)②Python 哲学『显式循环优于递归』不鼓励用递归模拟循环③实现复杂收益小;所以从 Scheme/Haskell 带来的『尾递归=循环』直觉在 Python 不成立;★深递归的正确解法:线性递归改成 for 循环、树/图递归改成『显式栈+while』(stack=[root];while stack:node=stack.pop();stack.extend(children),把递归的隐式调用栈换成自己管理的列表、不受深度限制)、重复子问题用记忆化 lru_cache;sys.setrecursionlimit(n)能调高但只抬软限制、C 栈物理上限还在、调太高会真的段错误崩溃,一般说明该改迭代了」

七、常见误区与追问

  • 误区:Python 的递归深度限制可以随便调大来支持深递归。 不建议——sys.setrecursionlimit(n) 只是抬高 Python 层的「软限制」,但底层 C 调用栈还有物理上限(栈空间是操作系统分配的、几 MB),如果调得太高、软限制过了但 C 栈实际耗尽,会导致解释器「段错误崩溃」(segfault、无法 try/except、无堆栈信息),比 RecursionError 糟糕得多;需要处理深度可能很大的递归时,正确做法是改成迭代或显式栈,而不是盲目调高限制。
  • 误区:写成尾递归 Python 就会优化成循环、不受深度限制。 不会——Python 故意不做尾递归优化(TCO),即使递归调用是函数的最后一个动作,Python 照样为每次调用压一个新栈帧,所以尾递归和普通递归一样受深度限制、fact_tail(2000) 照样 RecursionError;从 Scheme、Haskell 等会做 TCO 的语言转来的人常有这个误解;在 Python 里深递归必须手动改成循环或显式栈。
  • 误区:RecursionError 一定是代码有 bug(无限递归)。 不一定——RecursionError 有两种情况:① 真的无限递归(忘了基线条件、或基线条件永远不满足),这是 bug;② 递归本身正确、但深度确实超过了限制(比如遍历一棵很深的树、处理很长的链表、大 n 的递归),这不是逻辑 bug 而是「递归深度超限」;第一种要修基线条件,第二种要改成迭代/显式栈(或谨慎调高限制);看到 RecursionError 先判断是哪种。
  • 误区:递归和迭代性能一样,只是写法不同。 在 Python 里递归通常更慢、更耗内存——每次递归调用都有函数调用开销(压栈帧、传参、Python 解释器的调用机制),而迭代只用一个栈帧、复用变量;同样的逻辑(如阶乘、求和),迭代版本一般比递归快、且不占额外栈空间、无深度限制;所以性能敏感或深度可能大的场景优先用迭代,递归主要用在「深度可控且递归写法更清晰」的地方(树遍历、分治、回溯)。
  • 追问:Python 为什么要限制递归深度,这个限制是怎么起作用的? 因为每次函数调用都会在「调用栈」上压入一个栈帧(保存该次调用的局部变量、参数、返回地址等),栈帧会一直保留到该次调用返回;递归越深、同时存在的栈帧越多、占用的栈空间越大,如果无限递归或递归极深就会耗尽栈空间导致崩溃;Python 设置了一个默认约 1000 的「软限制」,在每次函数调用时检查当前递归深度,一旦超过就主动抛出 RecursionError(一个正常的 Python 异常,可以被捕获、有清晰的堆栈信息)——这样把「C 栈溢出导致的段错误崩溃」(无法恢复、没有有用信息)转化成了「可控的 Python 异常」,既防止了崩溃又给出了友好提示;这个限制包括解释器内部的调用帧,所以实际能达到的用户递归层数可能略少于 1000。
  • 追问:Python 为什么不实现尾递归优化,别的语言(如 Scheme)为什么做? Scheme、Haskell 等函数式语言把递归作为主要的循环手段、语言规范要求做尾递归优化(尾调用时复用当前栈帧、不增长栈),所以在它们里「尾递归 = 循环」、可以无限深;Python 的作者 Guido 明确拒绝加 TCO,主要理由有:① 尾递归优化会「压平」调用栈,破坏完整的堆栈回溯(traceback),而 Python 非常重视调试时能看到完整清晰的调用链;② Python 的设计哲学是「显式循环优于递归」,不希望鼓励开发者用递归去模拟循环(那样不 Pythonic);③ 隐式的优化违反「显式优于隐式」的原则,而且实现复杂、收益有限;所以 Python 定位不是函数式语言、递归只是众多工具之一,深循环该用 for/while。
  • 追问:遇到深度可能超限的递归(比如遍历很深的树),应该怎么改写? 把「递归的隐式调用栈」改成「自己管理的显式栈 + 循环」:递归 DFS def dfs(node): visit(node); for c in node.children: dfs(c) 可以改成 def dfs(root): stack = [root]; while stack: node = stack.pop(); visit(node); stack.extend(reversed(node.children))——用一个列表当栈、pop 取出节点处理、把子节点压回栈,直到栈空;这样递归深度就变成了列表长度、只受内存限制而非递归深度限制;BFS 则用队列(collections.deque)代替栈;线性递归(阶乘、求和、链表遍历)直接改成 for/while 循环;有重复子问题的(如斐波那契)先用记忆化(@lru_cache)减少调用次数、深度大时再配合迭代;总之核心是「把递归换成迭代 + 自己维护的数据结构」,避开 Python 的递归深度限制。

八、加强记忆

Python 默认限制递归深度约 1000(sys.getrecursionlimit()),超过抛 RecursionError: maximum recursion depth exceeded为什么有限制:每次函数调用在调用栈压一个「栈帧」(存局部变量/参数/返回地址),递归太深耗尽栈空间;Python 用「软限制」在真正崩溃前主动抛 Python 异常(可 try/except、有清晰堆栈,比 C 栈段错误崩溃友好得多)。Python 故意不做「尾递归优化(TCO)」——即使写成尾递归(return f(n-1, acc*n)),Python 也照常压栈帧、仍会超限;Guido 明确拒绝,理由:① 破坏完整栈回溯(调试看不到调用链)、② Python 哲学「显式循环优于递归」(不鼓励用递归模拟循环)、③ 实现复杂收益小;所以从 Scheme/Haskell 带来的「尾递归 = 循环」直觉在 Python 不成立。深递归的正确解法:线性递归改成 for 循环、树/图递归改成「显式栈 + while」(stack = [root]; while stack: node = stack.pop(); stack.extend(children),把递归的隐式调用栈换成自己管理的列表、不受深度限制)、重复子问题用记忆化 lru_cachesys.setrecursionlimit(n) 能调高但只抬软限制、C 栈物理上限还在、调太高会真的段错误崩溃(一般说明该改迭代了)。一句话「递归深度默认约 1000(超抛 RecursionError、软限制比崩溃友好);Python 不做尾递归优化(Guido 拒绝:破坏栈回溯+显式循环优于递归),尾递归也受限;深递归改成迭代/显式栈+while/记忆化,别轻易调 setrecursionlimit(调太高真崩溃)」。