Python递归指函数在运行过程中再次调用自身。它适合能拆成同类、规模更小的子问题的场景,例如阶乘、树形结构遍历。写递归时通常要同时想清楚两件事:何时停止(基线条件),以及如何把规模缩小后再调用自己。
阶乘的递归写法
n 的阶乘可以定义成 n 乘以 (n-1) 的阶乘,并规定 1 的阶乘是 1。后半句就是基线,前半句就是递归步骤:
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120两个关键部分
- 基线条件:规模小到可以直接给出答案,不再调用自身。缺了它,调用会一直叠下去,最终触发
RecursionError。 - 递归步骤:把当前问题化成规模更小的同类问题,再调用自己,并在返回后组合出当前答案。
factorial(4) 怎么展开
调用会先一路深入到基线,再带着返回值往回乘。左侧是递推拆小,右侧是回溯汇总:
factorial(4) 先一路递推到基线 factorial(1),拿到 1 后再从下往上回溯:1 → 2 → 6 → 24。调用栈先压后弹。
factorial(4)
= 4 * factorial(3)
= 4 * (3 * factorial(2))
= 4 * (3 * (2 * factorial(1)))
= 4 * (3 * (2 * 1))
= 24
斐波那契数列
每一项等于前两项之和,于是自然出现两次递归调用。这种朴素写法在 n 变大时会重复计算大量子问题,思路清楚,但性能差,实际工程里常改成循环或加缓存:
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
for i in range(8):
print(fib(i), end=" ")
print()递归和循环
| 维度 | 递归 | 循环 |
|---|---|---|
| 表达 | 贴近分治、树形定义 | 需自己维护状态变量 |
| 开销 | 每次调用占一层栈帧,过深会溢出 | 通常更省、更快 |
| 适用 | 目录树、表达式树、分治 | 大多数线性重复 |
递归深度上限
CPython 默认把递归深度限制在大约一千层,超出就抛 RecursionError。可以用 sys.setrecursionlimit 调大,但更深往往意味着该改算法,而不是一味加限额:
import sys
sys.setrecursionlimit(5000)目录树遍历
子目录里还有子目录,结构自身就是递归的。用 os 列出当前层,遇到目录再对自己调用一次,就能打印整棵树:
import os
def walk(dir_path, depth=0):
for item in os.listdir(dir_path):
full = os.path.join(dir_path, item)
print(" " * depth + item)
if os.path.isdir(full):
walk(full, depth + 1)
walk(".")注意事项
- 漏写基线条件,或基线永远达不到,会陷入无限递归。
- 基线写错(例如阶乘用
n == 0却从负数开始)会导致结果错误或无法终止。 - 深度过大时优先改成循环、显式栈或分治加缓存,而不是只靠提高递归上限。