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

Python pathlib.Path.rglob 怎样排除构建目录

来源:17golang原创

时间:2026-10-26 04:16:47 461浏览 收藏

用 pathlib.Path.rglob() 扫描 Python 项目时,最容易出现的结果是:源码找到了,build、dist、__pycache__ 里的生成文件也一起进来了。稳定的处理方式不是把模式写得越来越复杂,而是把“递归匹配”和“目录排除”分成两层:先用 rglob 找到候选路径,再用 Path.parts 判断完整目录段。

官方文档:https://docs.python.org/3/library/pathlib.html#pathlib.Path.rglob

这样既保留了 Path 对不同操作系统路径的处理,也不会因为目录名只是某个字符串的一部分而误删文件。下面以“收集项目中的 Python 源文件”为例,整理一套可复用的筛选结构。

先把 rglob 的职责限定在递归匹配

rglob(pattern) 会从当前路径递归寻找符合模式的路径对象。它适合表达“我要哪些后缀”,例如 *.py;但它不是一个完整的排除配置器。把所有黑名单都塞进 glob 模式,遇到多级目录和平台差异时反而难读。

from pathlib import Path

root = Path("project")

# 这里只声明候选类型:递归找到所有 Python 文件。
candidates = root.rglob("*.py")

# rglob 返回 Path 对象,后续可以继续读取 parts、suffix 和 name。
for path in candidates:
    print(path)

把 rglob 看成“输入候选路径”的入口后,真正的过滤条件就可以独立测试、独立扩展。

Path.rglob 从项目根目录产生候选路径并连接到后缀与路径段筛选的静态结构说明图
图1:结构说明图,展示 rglob 候选路径、后缀判断与目录段判断之间的静态关系,不是运行截图。

用 parts 排除完整目录段

不要用 "build" in str(path) 作为唯一判断。它可能把 build-tools 或文件名中带有 build 的路径误认为构建目录。Path.parts 会把路径拆成目录段,黑名单只命中独立段时才排除。

from pathlib import Path

EXCLUDED_DIRS = {"build", "dist", "__pycache__", ".venv"}

def is_source_file(path: Path) -> bool:
    # 只排除完整路径段,避免误伤 build-tools 或 rebuild.py。
    has_excluded_dir = any(part in EXCLUDED_DIRS for part in path.parts)
    # 后缀判断保持简单,让排除规则和文件类型各自负责一件事。
    return path.is_file() and path.suffix == ".py" and not has_excluded_dir

def collect_sources(root: Path) -> list[Path]:
    # 先递归收集候选,再统一过滤,方便增加新的目录规则。
    sources = (path for path in root.rglob("*.py") if is_source_file(path))
    # 排序让构建日志、缓存键和后续处理顺序保持稳定。
    return sorted(sources)

这里的两个判断层次很清楚:suffix 决定文件类型,parts 决定它是否位于被排除的目录。若只想跳过名为 build 的顶层目录,也可以把判断改成相对路径的第一段,但要先明确扫描根目录。

Path.parts 将项目路径分成允许源码区与 build dist 缓存目录区的边界结构说明图
图2:边界说明图,展示完整路径段如何把源码目录与生成目录分开,不代表真实运行结果。

把筛选器做成可维护的收集函数

工程代码里建议让黑名单成为显式配置,而不是散落在多个生成器表达式中。上面的 collect_sources 还带来了三个好处:调用方得到普通的 list[Path],可以在需要时排序;过滤函数能单独测试;将来加入 tests、examples 等规则时只改集合。

如果项目允许目录名大小写变化,应先定义策略。Linux 路径通常区分大小写,Windows 常见文件系统可能不区分;不要未经决定就把所有路径统一小写,否则会掩盖真实文件名。更稳妥的做法是根据项目约定生成黑名单,或者只匹配仓库中实际约定的目录名。

几个容易漏掉的边界

  • 空结果:没有符合条件的源码时返回空列表是正常结果,调用方不要把它当成异常。
  • 符号链接:如果扫描范围包含链接目录,要按项目安全策略决定是否允许跟随;不要把它和普通目录排除混在一起。
  • 相对路径:使用 parts 前先确认黑名单针对的是绝对路径还是相对项目根的路径,避免根目录名称碰巧撞名。
  • 稳定顺序:递归遍历的自然顺序不应当作为业务顺序,交给 sorted() 明确固定结果。

可以把最终判断概括为:rglob 负责找到候选,suffix 负责类型,parts 负责目录边界,sorted 负责稳定输出。这样排除构建目录时,规则既直观,又不会随着项目目录层级增加而失控。

相关问题

Path.rglob("**/*.py") 和 Path.rglob("*.py") 有什么区别?
都用于递归查找时,优先使用更直接的 *.py 表达目标;关键差别不在排除目录,而在后续筛选是否清晰。

为什么不直接用 glob 排除目录?
复杂排除通常会让模式变得难以解释。把目录黑名单放到 parts 判断中,更容易测试和扩展。

只排除当前根目录下的 build 怎么写?
把路径转换成相对根目录后的 parts,只检查第一段是否为 build,不要对完整绝对路径做模糊字符串搜索。

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