登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  python教程

Python pathlib.glob 怎么排除隐藏目录并保持递归

来源:17golang原创

时间:2026-09-08 14:26:38 142浏览 收藏

如果用 Path(".").glob("**/*.py") 扫描项目,pathlib 不会把以点开头的文件或目录视为特殊项,隐藏目录里的 Python 文件也可能被返回。要保留递归能力,关键不是把模式改成更复杂的通配符,而是在匹配结果上检查每个路径部件:只要父级目录中有一个以点开头的名称,就跳过该路径。

要点速览
  • glob("**/*") 会递归匹配,隐藏目录不会自动排除。
  • any(part.startswith(".") for part in path.relative_to(root).parts[:-1]) 过滤任意层级的隐藏目录。
  • 最后再调用 is_file(),需要稳定输出时显式 sorted(),不要把扫描顺序当成排序结果。

为什么 glob 的递归模式会进入隐藏目录

Path.glob() 接收相对模式并返回匹配到的文件系统对象,** 组件会递归展开;Path.rglob() 可以看作在模式前补上递归前缀。与部分命令行工具的默认习惯不同,pathlib 中以点开头的名称不自动获得“隐藏”语义,所以 .cache/data.py.git/hooks/check.py 都可能进入结果。

这也是为什么只写 root.rglob("*.py") 不够:它能保持递归,却没有表达“不能经过隐藏目录”这个业务条件。过滤目录名称比事后排除文件名更准确,因为它能同时处理任意深度的隐藏目录。

Python pathlib glob 递归匹配与隐藏目录边界的静态关系图
图1:递归匹配会同时触达公开目录和隐藏目录,筛选条件需要作用于路径部件。

用 Path.parts 排除任意层级的隐藏目录

下面的函数保留 glob("**/*.py") 的递归能力,再把项目根目录之后的父级部件拿出来判断。文件本身以点开头不一定要排除,因此示例只检查 parts[:-1],也就是父目录;如果你的规则连隐藏文件也不需要,可以把切片改成完整的 parts

from pathlib import Path


def visible_python_files(root: Path) -> list[Path]:
    """递归查找 Python 文件,但不进入隐藏目录。"""
    result = []
    for path in root.glob("**/*.py"):
        relative_parts = path.relative_to(root).parts
        parent_parts = relative_parts[:-1]
        # 任意父目录隐藏,就跳过该文件;文件名本身暂不限制。
        if any(part.startswith(".") for part in parent_parts):
            continue
        # glob 可能匹配目录或特殊文件,最终只保留普通文件。
        if path.is_file():
            result.append(path)
    return sorted(result)


for file_path in visible_python_files(Path("project")):
    print(file_path)

这里的 relative_to(root) 让判断与根目录无关;parts 是路径各段组成的元组,比直接对字符串做 "/." 搜索更不容易受到 Windows 分隔符影响。sorted() 也很重要,因为官方文档明确说明 glob 返回顺序没有保证。

文件过滤、排序和符号链接怎么取舍

可以把几个容易混在一起的条件拆开处理:

条件推荐写法解决的问题
递归匹配glob("**/*.py")rglob("*.py")覆盖多层公开目录
跳过隐藏目录检查 relative_path.parts[:-1]不误入任意深度的点目录
只要文件path.is_file()排除目录及非普通文件
稳定顺序sorted(result)避免依赖文件系统遍历顺序

符号链接是另一条边界。当前 Python 文档中,glob() 展开 ** 时默认不递归跟随符号链接;如果业务确实要跟随,需要显式考虑 recurse_symlinks=True,同时防范链接把扫描范围带到项目根目录之外。对于清理、索引或上传任务,默认不跟随通常更容易控制范围。

Pathlib 路径部件过滤、文件类型检查和排序顺序关系图
图2:先判断路径部件,再确认文件类型,最后排序输出,三个条件各自解决不同问题。

封装时的检查清单与常见问题

项目里复用这段逻辑时,建议先确定四件事:隐藏目录是只排除父目录,还是连隐藏文件也排除;结果是否必须按路径排序;权限异常是否允许跳过;符号链接是否允许扩大递归范围。不要用“结果数量变少”作为唯一判断,最好准备一个公开目录、一个嵌套隐藏目录和一个隐藏文件做小样本检查。

如果只想排除常见的 .git,也可以把父目录部件与集合比较;但“所有以点开头的目录”更适合用 startswith(".") 表达。若扫描目录可能不存在,先用 root.is_dir() 给出明确错误;不要把空结果误认为过滤成功。

相关问题

pathlib.glob 会自动跳过 .git 吗?

不会。pathlib 的点文件和点目录不自动特殊处理,需要在结果或遍历阶段自行过滤。

glob 和 rglob 哪个更适合递归查找?

两者都可以;模式较复杂时用 glob("**/*.py") 更直观,只有一个文件模式时用 rglob("*.py") 更简洁。

为什么结果顺序每次可能不同?

glob 不保证返回顺序。需要稳定输出、测试快照或生成清单时,显式调用 sorted()

参考:Python pathlib 官方文档

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>