一段导出目录树的脚本,跑到第三层就抛 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 不做尾递归优化,别指望靠尾调用省栈。