os.walk能动态跳过子目录而glob不能,因其允许在迭代中就地修改dirs列表;返回(root, dirs, files)三元组便于结构化处理;支持符号链接控制、排序过滤、手动迭代控制、跨平台路径拼接及错误恢复,但需显式管理路径与类型判断。

os.walk能动态跳过子目录,glob做不到
当你需要根据目录名或权限决定是否进入某一层时,os.walk允许你在每次迭代中就地修改dirs列表——比如跳过__pycache__、.git或临时构建目录。而glob.glob("src/**/*.py", recursive=True)是“全量递归”,无法在遍历中途干预路径选择。
常见错误是直接用dirs.remove()或del dirs[0],这会破坏迭代器状态;正确做法是dirs[:] = [d for d in dirs if not d.startswith(('.', '_'))],保证原列表被替换而非重建。
os.walk返回结构化元组,便于同时处理文件和目录
os.walk每次yield的是(root, dirs, files)三元组,意味着你能同时拿到当前路径、子目录名列表和文件名列表。比如要统计每层目录下.py文件数、生成目录树摘要、或只对含requirements.txt的目录做操作,都依赖这个结构。
glob.glob()只返回扁平的路径字符串列表,哪怕加了recursive=True,你也得自己用os.path.dirname()反复解析才能还原层级关系,既慢又易错。
立即学习“Python免费学习笔记(深入)”;
- 想跳过符号链接?
os.walk(followlinks=False)默认就安全,glob不支持该语义 - 要按修改时间排序后再处理?
dirs.sort(key=lambda d: os.stat(os.path.join(root, d)).st_mtime)可直接作用于dirs - 需过滤掉无读取权限的目录?
dirs[:] = [d for d in dirs if os.access(os.path.join(root, d), os.R_OK)]
glob的递归是“黑盒”,os.walk的遍历是“白盒”
glob.glob("*.log")查当前层,glob.glob("**/*.log", recursive=True)查全部——但你无法知道它到底进了哪些目录、跳过了哪些、在哪一层匹配到结果。而os.walk每一步都暴露给你:你可以打印root观察路径、在files里提前break、甚至用next()手动控制迭代节奏。
性能上,这不是优势而是代价:当你要的是“所有.py文件路径”,glob通常更快;但如果你要的是“找到第一个含test_前缀的.py后,立即停止并返回其所在目录的父级”,os.walk配合return就能立刻退出,glob必须扫完整棵树再过滤。
跨平台路径处理和错误恢复更可控
os.walk返回的root和files都是相对于你传入起始路径的,拼接时用os.path.join(root, f)天然兼容Windows/Linux分隔符;glob则始终以os.getcwd()为基准,容易因工作目录变化导致路径错乱。
遇到PermissionError时,os.walk可在循环内try/except捕获并继续,而glob.glob()遇到权限拒绝会直接抛异常中断——除非你用pathlib.Path(...).rglob()配ignore_errors=True(Python 3.12+),但那是另一套API了。
真正容易被忽略的点是:os.walk的“灵活性”不是免费的——它要求你显式管理路径拼接、类型判断(os.path.isfile())、编码容错;而glob的“简单”背后是隐式约束,一旦需求超出通配符范围,就得切回os.walk重写逻辑。


















