正确做法是用 any(part == "node_modules" for part in path.parts) 判断路径是否含排除目录,或用 Python 3.12+ 的 Path.walk() 原地修改 dirs[:] 实现高效跳过;旧版本可封装 safe_rglob 函数配合 set 排除并处理符号链接与权限异常。

用 pathlib.Path.rglob 配合条件过滤跳过指定子目录
rglob 本身不支持排除路径,必须手动过滤。常见错误是试图用 ** glob 模式直接“否定”某个目录名——这在 pathlib 中不可行,模式只支持匹配,不支持排除。
正确做法是遍历全部,再用 parent 或 parts 判断路径是否落在要排除的目录下:
- 检查
path.parent.name == "node_modules"只能跳过一级子目录,漏掉src/node_modules/utils这类嵌套路径 - 更可靠的是用
path.parts遍历每一级目录名,或用str(path).startswith()做前缀判断(注意跨平台路径分隔符) - 推荐用
any(part == "node_modules" for part in path.parts),简洁且覆盖所有层级
用 pathlib.Path.walk(Python 3.12+)精准控制遍历行为
Python 3.12 引入的 walk 方法允许在进入子目录前修改 dirs 列表,实现真正意义上的“跳过”,避免无谓遍历:
for root, dirs, files in Path("project").walk():
# 在这里修改 dirs 列表,原地移除要跳过的目录名
dirs[:] = [d for d in dirs if d != "venv" and d != "__pycache__"]
for file in files:
print(root / file)
注意:dirs[:] 是关键,必须原地修改;直接赋值 dirs = [...] 无效。该方法比 rglob + 过滤更高效,尤其面对大量无关子目录时。
兼容旧版本 Python 的安全排除写法
若仍在用 Python os.walk 模拟相同逻辑,或封装一个带排除的 rglob 辅助函数:
def safe_rglob(root: Path, pattern: str = "*", exclude_dirs: set = None):
if exclude_dirs is None:
exclude_dirs = {"node_modules", ".git", "dist"}
for p in root.rglob(pattern):
if not any(part in exclude_dirs for part in p.parts):
yield p
使用
for pyfile in safe_rglob(Path("."), "*.py"):
print(pyfile)
这个函数的关键点在于:排除判断放在 yield 前,且作用于每个 p 而非仅顶层;exclude_dirs 用 set 保证 O(1) 查找;p.parts 自动处理不同系统的路径分隔符。
容易被忽略的符号链接与权限问题
默认情况下,rglob 和 walk 都会跟随符号链接,可能意外进入不该访问的路径,甚至触发循环引用。如果目标目录含软链,务必加判断:
- 用
p.is_symlink()提前跳过,或 - 在
walk中检查root / d是否为符号链接再决定是否保留到dirs - 遇到
PermissionError(如/proc下某些目录),需用try/except包裹,否则遍历中断
实际项目中,排除逻辑常和权限、符号链接、挂载点混在一起,光靠目录名过滤远远不够。










