用 pathlib 替代 os.path 的 8 个实用场景

举报
yd_222090921 发表于 2026/10/29 11:34:00 2026/10/29
【摘要】 从路径拼接到目录遍历,用 8 个真实场景对比 pathlib 与 os.path 的写法,附可运行示例和 5 个常见坑,帮你把路径代码写得更短更稳。

痛点:os.path 写多了像在做字符串体操

先看一段真实代码:

import os
base = "/data/report"
path = os.path.join(base, "raw", "2024", "a.csv")
if os.path.exists(os.path.dirname(path)):
    name = os.path.splitext(os.path.basename(path))[0]

四行代码,套了三层函数,眼睛得来回跳。问题不在于 os.path 有 bug,而在于它把「路径」当字符串处理:拼接靠函数调用,取父目录靠 dirname,取文件名靠 basename,改后缀靠 splitext 再手动拼回去。字符串拼错了不报错,跑起来才炸。

原理:Path 是对象,不是字符串

pathlib 把路径抽象成对象。Path 是具体实现,会根据系统自动变成 PosixPath 或 WindowsPath,所以同一份代码在 Windows 上分隔符自动是反斜杠。它重载了 / 运算符,Path("a") / "b" 等价于 os.path.join;所有方法都返回新的 Path 对象,原对象不变,链式调用不会互相污染。另外 Path 实现了 __fspath__,可以直接丢给 open()、os.stat()、shutil.copy() 这些老接口,不需要先转字符串。

8 个场景,一行换一行

  1. 拼接:Path("data") / "raw" / "a.csv",比 os.path.join("data", "raw", "a.csv") 短,也不会因为少写一个分隔符出错。
  2. 拆解:.name、.stem、.suffix、.parent,对应 basename、去掉后缀的名字、后缀、dirname。
  3. 判断:.exists()、.is_file()、.is_dir(),省掉 os.path 前缀。
  4. 建目录:.mkdir(parents=True, exist_ok=True) 一次搞定 os.makedirs 的递归和已存在报错。
  5. 遍历:.glob("*.py") 和 .rglob("*.log"),后者递归,不用手写 os.walk 循环。
  6. 读写:.read_text(encoding="utf-8")、.write_text(...),不用 with open 三行。
  7. 绝对路径:.resolve() 顶替 os.path.abspath 加 realpath,顺便解掉 .. 和符号链接。
  8. 改后缀:.with_suffix(".json")、.with_name("new.txt"),不用 splitext 再字符串相加。

可运行示例

from pathlib import Path

root = Path("demo_out")
root.mkdir(parents=True, exist_ok=True)

log = root / "logs" / "app.log"
log.parent.mkdir(parents=True, exist_ok=True)
log.write_text("hello\nworld\n", encoding="utf-8")

print(log.name, log.stem, log.suffix)   # app.log app .log
print(log.exists(), log.is_file())      # True True
print(log.read_text(encoding="utf-8").splitlines())  # ['hello', 'world']
print(log.with_suffix(".json").name)    # app.json
print([p.name for p in root.rglob("*.log")])  # ['app.log']
print(log.resolve().is_absolute())      # True

跑完会在当前目录生成 demo_out/logs/app.log,输出和注释一致。

几个容易踩的坑

第一,Path 不能和字符串相加。Path("a") + "/b" 直接 TypeError,要拼就继续用 /,要转字符串用 str(p) 或 f-string。

第二,Path("a") / "/b" 结果是 /b,因为右边是绝对路径会覆盖左边,和 os.path.join 行为一致,但很容易在变量拼接时忽略。

第三,相对路径是相对当前工作目录的,不是相对脚本文件。脚本里 Path("config.yaml") 取决于你在哪运行,用 Path(__file__).parent / "config.yaml" 才稳。

第四,.glob("*") 会带出隐藏文件,而 glob 模块的 glob.glob("*") 默认不会,两套 API 行为不一致,迁移时注意。

第五,.resolve() 默认不要求路径存在,路径不存在也能返回绝对路径,但涉及符号链接时语义和老代码的 realpath 有细微差别,最好显式测一遍。

小结

os.path 没被废弃,处理纯字符串路径、和老代码兼容时照样能用。但只要路径要参与判断、遍历、读写,Path 对象的链式写法更短也更难写错。建议新代码一律 from pathlib import Path,老代码碰到就顺手换,一次换一个函数,风险很低。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。