Skip to content

pathlib 为什么是神?路径解析推荐

当你在写机器人的时候,想必或多或少都有遇到过关于路径的问题吧。
而当你在 CSDN(床上等你) 搜索了一番以后, 你知道,在 Python 中都是用 os.path 来解析路径的。所以,你写出了这样的代码。

TIP

以下情节多少有点夸张,不过也不完全夸张。

python
import os
import os.path

# 得到文件所在目录下"资源"文件夹路径,如果不存在则创建它
source_folder = os.path.dirname(__file__) + r"/资源"
source_folder = os.path.join(os.path.dirname(__file__), "资源")
if not os.path.exists(source_folder):
    os.makedirs(source_folder)

# 获取这些文件中所有 jpg png 格式文件的文件名
source_name = [
    os.path.split(p)[1][-4] for p in os.listdir(source_folder)
    if os.path.splitext(p)[1] in [".jpg", ".png"]
]
source_name = [
    os.path.splitext(os.path.split(p)[1])[0] for p in os.listdir(source_folder)
    if os.path.splitext(p)[1] in [".jpg", ".png"]
]

# 将一个绝对路径的文件复制到根目录同名的压缩包里面
from zipfile import Zipfle
file = "/a/b/c/d.txt"
compress_file = os.path.splitext(os.path.split(p)[1])[0] + ".zip"
with Zipfile(compress_file, "w") as myzip:
    myzip.write(file)

# 读取文件,否则创建文件
if os.path.exists(os.path.join(source_folder, "config.json")):
    with open(os.path.join(source_folder, "config.json"), "r", encoding="UTF-8") as f:
        config = json.load(f)
else:
    with open(os.path.join(source_folder, "config.json"), "w", encoding="UTF-8") as f:
        json.dump({"config": {}}, f)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

说实话,这一点都不 Pythonic,不是吗? 难道就没有更优雅的写法了吗?

当然有啊,那就是 pathlib

pathlib 是什么

pathlib 提供表示文件系统路径的类,其语义适用于不同的操作系统。

你可能听不太懂,我们还是直接举例吧。我们把上面的例子,用 pathlib 重新写一遍

python
from pathlib import Path

# 得到文件所在目录下"资源"文件夹路径,如果不存在则创建它
source_folder = Path(__file__).parents / "资源"
source_folder.mkdir(exist_ok=True)

# 获取这些文件中所有 jpg png 格式文件的文件名
source_name = [p.stem for p in source_folder.iterdir() if p.suffix in [".jpg", ".jpeg", ".png"]]

# 将一个绝对路径的文件复制到根目录同名的压缩包里面
from zipfile import Zipfle
file = "/a/b/c/d.txt"
compress_file = Path(Path(file).name).with_suffix(".zip")
compress_file = Path(file).name
with Zipfile(compress_file, "w") as myzip:
    myzip.write(file)

# 读取文件,否则创建文件
config_path = source_folder / "config.json"
if config_path.exists:
    config = json.loads(config_path.read_text(encoding="UTF-8"))
else:
    config = config = {"config": {}}
    config_path.write_text(config, encoding="UTF-8")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

先说一说直观上的东西:

python
Path("a", "b")
Path() / "a" / "b"
1
2

在 Windows 和 Linux 上,路径的分隔符其实是不一样的。

  • 在 Windows 上,分隔符是正斜杠 /
  • 在 Linux 上,分隔符是反斜杠 \

但是在 Path 中,你可以直接通过 Path 重定义 / 运算符 来做到路径的解析。
而让你通过 str(Path()) 来获取路径字符串的时候,Path 将根据所在系统自动判断是否 / 还是 \

Path 多到爆表的属性

当你在使用 Path 来表示你的路径的时候,你会有相当多的属性来帮助你

TIP

因为 Path 类会自动选择是 Windows 用的的 WindowsPath 还是 Unix 用的的 PosixPath, 所以最后显示出来的应该是 WindowsPath 或者 PosixPath,而不是 Path

python
>>> p = Path('a/b/c/d.txt')
>>> p.parent # 所在文件夹
Path('a/b/c')
>>> p.name # 名字
'd.txt'
>>> p.stem # 名字(不带后缀)
'd'
>>> p.suffix # 后缀
'.txt'
>>> p.suffixes # 后缀s (如 .tar .gz)
['.txt']
1
2
3
4
5
6
7
8
9
10
11

Path 类有的多到爆表的方法

python
p = Path('a/b/c')
f = p / "d.txt"

f.is_dir() # 是否是文件夹
f.is_file() # 是否是文件
f.exists() # 是否存在
f.rename("e.txt") # 将 "d.txt" 重命名为 "e.txt"
f.read_text(encoding="UTF-8") # 以 "UTF-8" 编码读取文件
f.read_bytes() # 以二进制形式读取文件
f.write_text("F", encoding="UTF-8") # 以 "UTF-8" 编码写入文件
f.write_bytes(b"F") # 以二进制形式写入文件
with f.open("r") as fp: ... # 打开文件,就像内置 open 一样
f.stat().st_size # 获取文件大小

# 创建文件夹,如果父级文件没创建,也创建父级文件夹
# 如果文件夹已经存在,那就存在了,也不会报错
p.mkdir(parents=True, exists_ok=True)
p.iterdir() # 以 iter 的形式获取文件夹里的文件


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

所以,我到底应该什么时候使用呢ta呢?

首先,假设你只是写一个不需要变更的路径,如: ./static/font/xxx.ttf
那么你就直接写字符串就行了, 因为你只是将这个路径传给其他第三方库,而并不需要操作路径,或者读取/写入文件。

pathlib 更多的是用在那些你需要操作路径、文件操作的地方, 所以,不要一看到路径就用 pathlib。

Tip:

本文档使用 CC BY-NC-SA 4.0 协议进行共享,详情见 README

MIT License