pathlib 默认 rglob("*") 会遍历隐藏项,需手动用 name.startswith(".") 过滤;若要跳过整个隐藏目录及其子内容,须改用 iterdir + 递归实现剪枝。

pathlib 递归遍历如何过滤 . 开头的隐藏项
默认 Path.rglob("*") 会包含所有匹配项,包括以 . 开头的隐藏文件和目录(如 .git、.env)。pathlib 本身不提供内置“跳过隐藏项”参数,必须手动过滤。
用 name.startswith(".") 过滤最直接可靠
Unix/Linux/macOS 和大多数 Python 场景下,“隐藏”即指文件名以 . 开头。Windows 虽不原生依赖此约定,但项目中仍普遍沿用该命名习惯(如 .vscode)。
实操建议:
- 对每个
Path对象检查item.name.startswith("."),不是item.stem或item.suffix - 注意:要同时过滤隐藏文件和隐藏目录,所以判断应在遍历时做,而非只对最终文件做
- 避免用
os.path.isdir()或item.is_dir()额外判断——rglob返回的已含目录,且is_dir()可能触发额外 I/O
示例:
from pathlib import Path
root = Path(".")
for item in root.rglob("*"):
if item.name.startswith("."):
continue
print(item)
想排除整个隐藏目录及其子内容?得用 iterdir + 手动递归
rglob 是深度优先且无法“剪枝”——一旦进入 .git/,它仍会遍历里面所有 .git/objects/...。若目标是彻底跳过整个隐藏目录(不进其内部),就不能用 rglob,而需自己控制遍历逻辑。
实操建议:
- 用
Path.iterdir()获取当前层子项,先过滤掉.name.startswith(".")的项 - 对留下的每一项,如果是目录,再递归调用;如果是文件,直接处理
- 这样可确保
.venv/这类目录完全不会被进入,性能更好,也更符合“跳过隐藏目录”的直觉
简版递归函数示例:
def walk_no_hidden(p: Path):
for item in p.iterdir():
if item.name.startswith("."):
continue
if item.is_dir():
yield from walk_no_hidden(item)
else:
yield item
注意跨平台兼容性:不要依赖 stat().st_file_attributes
Windows 上可通过 item.stat().st_file_attributes & stat.FILE_ATTRIBUTE_HIDDEN 判断系统级隐藏属性,但:
- 绝大多数 Python 项目中的“隐藏”是靠命名约定(
.开头),不是系统属性 - macOS 的
.DS_Store是命名隐藏,不是属性隐藏 - 混合环境(如 Windows 上开发 macOS 目标项目)下,只认
.前缀才能保持行为一致
所以除非你明确要支持 Windows 资源管理器里手动勾选“隐藏”的文件,否则一律用 name.startswith(".") 更简单、稳定、可预期。
真正容易被忽略的是:rglob 不区分“是否进入”,只要路径匹配就返回——哪怕你后续 continue,它已经把整个 .git 树都生成出来了。需要剪枝就得换遍历方式。










