一段导出目录树的脚本,跑到第三层就抛 RecursionError: maximum recursion depth exceeded,可目录实际有七层。把深度限制调大照样炸,最后发现是两个目录互相软链接,绕成了环。

递归就是函数调自己,每层压一个栈帧。Python 默认上限 1000 层,超过就抛异常;目录不深也炸,通常是遇到了环,或者每层开了新分支。

先确认有没有环

os.walk 默认 followlinks=False,不会跟进软链接,自己手写的递归没有这道闸。做法是用 realpath 归一化后记下来,走过的不再进。

seen = set(); real = os.path.realpath(p); if real in seen: return; seen.add(real)

栈深度不是随便调的

sys.setrecursionlimit(100000) 只是把崩溃点往后推,C 栈照样会溢出,进程直接段错误,比抛异常更难查。真要跑深结构,改成迭代加显式栈。

stack = [root]; while stack: cur = stack.pop(); stack.extend(children(cur))

显式栈还有个好处:能随时暂停、记录进度、按层输出,递归做不到这些。

什么时候递归反而合适

分治、归并排序、JSON 嵌套解析、表达式求值,这些结构本身就是递归定义的,深度稳在几十层,写递归比循环清楚。树形菜单渲染也一样,层级由业务限制,不会失控。

另一个容易忽略的触发点是递归里缓存中间结果,每层存一份,内存和调用栈一起涨。把中间态挪到函数外面,或者给缓存加个容量上限,能压住增长。

判断标准就一条:深度有没有上限。有上限且不大,递归好读;没上限、跟着用户数据走,一律改迭代。Python 不做尾递归优化,别指望靠尾调用省栈。