yield from 通过解释器级委托机制简化递归遍历,自动透传控制流与异常,避免缩进套娃、中断遍历及状态污染,但需注意资源泄漏风险。

因为它把嵌套生成器调用从“手动展开”变成“自动委托”,递归逻辑不再需要缩进套娃,控制流和异常也原样透传。
为什么手动递归遍历目录容易写错
常见写法是 os.scandir() + 多层 for 嵌套 + yield,问题集中在这几处:
- 每层递归都得写
for sub in old_traverse(entry.path): yield sub,缩进深、易漏项 - 遇到
PermissionError时,for循环直接中断整个遍历,无法跳过继续 - 想在某一层提前退出(比如只遍历前100个文件),得加状态变量和
break,逻辑污染主干 - 如果子生成器返回值(比如统计子目录文件数),手动循环没法自然捕获,得额外变量中转
yield from 如何让递归遍历变扁平
它不是语法糖,而是解释器级的委托机制——执行到 yield from clean_traverse(entry.path) 时,Python 直接把当前生成器的 next()、send()、throw() 全部转发给子生成器,直到它耗尽或出错。
- 代码从 6 行缩进压成 1 行:
yield from clean_traverse(entry.path) - 权限错误发生在子生成器里?它自己
try/except后continue,主生成器完全不受影响 - 子生成器用
return 42结束?这个42会成为yield from表达式的值,可被主生成器直接接收 - 内存只维持当前路径栈帧,不会因目录深度增加而累积调用栈(
RecursionError是递归本身的问题,不是yield from导致的)
容易被忽略的资源泄漏风险
yield from 的委托是“全有或全无”的:一旦交出控制权,你就不能再部分消费子生成器——要么让它跑完,要么显式调用 .close()。
- 如果中途丢弃一个正在用
yield from委托的生成器(比如没迭代完就跳出for循环),且子生成器内部打开了文件句柄或网络连接,这些资源可能不会释放 - 手动循环至少还能在
except里补entry.close();而yield from委托后,你失去了对子生成器生命周期的直接控制权 - 解决方案只有两个:确保子生成器自身做资源清理(比如用
with包裹os.scandir()),或者在外层明确调用gen.close()
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











