glob.glob() 默认不递归,必须显式传 recursive=true 才启用 通配符;漏掉该参数或路径中缺少分隔符(如 src/.py)均导致匹配失败且静默返回空列表。

glob.glob() 默认不递归,必须显式传 recursive=True
很多人写 glob.glob("*.py") 发现只扫当前目录,根本找不到子目录里的文件——这不是 bug,是 glob 的默认行为。Python 3.5+ 引入 recursive 参数,但它的值默认是 False,必须手动设为 True 才能进子目录。
同时,** 通配符必须配合 recursive=True 才生效,单独写 "**/*.py" 却不传参数,结果为空列表,且不会报错,非常容易被忽略。
-
glob.glob("src/**/*.py", recursive=True)✅ 正确:从src/开始递归找所有.py -
glob.glob("src/**/*.py")❌ 错误:recursive缺失,**被当字面量处理,匹配不到任何路径 -
glob.glob("src/*.py", recursive=True)⚠️ 无效:没用**,递归参数不起作用,仍只查src/一级
用 ** 时路径开头别漏斜杠,否则可能匹配失败
** 表示“任意深度的子目录”,但它对路径结构敏感。常见错误是写成 "**.py" 或 "src/**.py" —— 这些都不合法,glob 会静默返回空列表,而不是抛异常。
正确写法必须包含路径分隔符(/ 或 \),让 glob 明确知道 ** 是在做目录层级匹配:
-
glob.glob("**/*.py", recursive=True)✅ 从当前目录起全盘扫描 -
glob.glob("src/**/*.py", recursive=True)✅ 限定根目录为src/ -
glob.glob("src/**.py", recursive=True)❌**后缺/,glob 不识别为递归模式
Windows 下用 os.path.join() 拼接更安全,但 glob 内部自动适配路径分隔符,直接写 / 在 Windows 也能工作。
注意 glob.escape() 对含特殊字符路径的保护
如果搜索路径里有 [、?、* 这类 glob 元字符(比如目录名是 my[project]),不加处理会导致匹配逻辑错乱。这时候不能靠引号或转义字符串硬扛,得用 glob.escape()。
例如想递归查 my[proj]/ 下所有 .log 文件:
import glob
base = glob.escape("my[proj]")
paths = glob.glob(f"{base}/**/*.log", recursive=True)
漏掉 glob.escape(),[proj] 会被解释为字符集匹配,很可能什么也搜不到,还难以排查。
性能和跨平台兼容性:pathlib.Path.rglob() 更推荐用于新项目
glob 模块简单直接,但 pathlib 的 rglob() 方法语义更清晰、API 更一致,且自动处理路径拼接和编码问题:
-
Path("src").rglob("*.py")✅ 不需要recursive=参数,天然递归 - 返回
Path对象,后续调用.stem、.suffix、.read_text()更自然 - 在 Python 3.4+ 全版本可用,Windows/macOS/Linux 行为完全一致
如果你的项目已用 pathlib 管理路径,强行切回 glob 反而增加心智负担。只有在极简脚本或需与旧代码保持风格一致时,才优先选 glob。
真正容易被忽略的是 ** 和 recursive=True 的绑定关系——它不像其他参数那样“可选但默认有效”,而是非此即彼的开关。少写一个,整个递归就失效,且毫无提示。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











