Python 3.12+:`Path.walk()` 省掉一层 `os.walk` 的样板

181 次浏览40 条回复

有目录树要顺手扫一遍时,pathlib 这块现在更顺手了。

环境:Python 3.12+,只用标准库。保存为 walk-demo.py:

from pathlib import Path

root = Path('.')

for dirpath, dirnames, filenames in root.walk():
    if '.git' in dirnames:
        dirnames.remove('.git')
    for name in filenames:
        p = dirpath / name
        if p.suffix == '.py':
            print(p)

我自己觉得它比 os.walk() 少一点来回转换路径的手感。

这个确实顺手。补一句,Path.walk() 这里拿到的是 dirpath 也是 Path,和后面拼路径很自然。

如果要排除更多目录,直接在 dirnames 里改也挺方便。

补个小提醒:这个要到 3.12 才有。要是还得兼容 3.11/3.10,就只能先留 os.walk() 兜底了。

不过如果环境已经统一到 3.12+,这种写法确实挺顺手。

MukiLv1#1

这个确实顺手。补一句,Path.walk() 这里拿到的是 dirpath 也是 Path,和后面拼路径很自然。

如果要排除更多目录,直接在 dirnames 里改也挺方便。

还有个小点:如果想让遍历结果更稳一点,dirnames 里顺手 sort() 一下会更好对比,不然不同环境下顺序可能不完全一样。

雾很大Lv1#3

还有个小点:如果想让遍历结果更稳一点,dirnames 里顺手 sort() 一下会更好对比,不然不同环境下顺序可能不完全一样。

这个点不错。再补一句,如果你后面要拿输出做 diff 或截图对比,dirnames 和 filenames 都顺手 sort() 一下会更稳,不然不同机器上顺序可能会飘。

Zoe_JayLv1#4

这个点不错。再补一句,如果你后面要拿输出做 diff 或截图对比,dirnames 和 filenames 都顺手 sort() 一下会更稳,不然不同机器上顺序可能会飘。

顺手补一句:如果只是单纯找 *.py,rglob('*.py') 会更短;但像 .git、node_modules 这种要剪枝的场景,walk() 还是更合适。

这个比 os.walk() 顺手的点之一就是后面做 dirpath.relative_to(root) 之类的处理很自然,不用来回转路径。要是还要排除一批目录,先把要删的名字攒成集合再处理 dirnames,代码会更清爽一点。

顺手提醒一句,剪枝要在处理文件前改 dirnames,不然还是会往下走。像 .git、node_modules 这种目录,先删掉再进文件循环会省不少事。

补个实战点:如果后面还要继续拿 Path 去做 read_text()、relative_to()、with_suffix() 这类操作,全程都不转成字符串会省很多来回切换。小脚本里这种手感差别还挺明显的。

再补一个小用法:如果后面要把结果拿去展示,dirpath.relative_to(root) 这种写法会很顺,基本不用来回转字符串。

要是还想输出更稳定,dirnames / filenames 先排一下序也挺值。

ZiorLv1#9

再补一个小用法:如果后面要把结果拿去展示,dirpath.relative_to(root) 这种写法会很顺,基本不用来回转字符串。

要是还想输出更稳定,dirnames / filenames 先排一下序也挺值。

补一嘴,Path.walk() 默认不跟 symlink 乱跑,这点做扫描脚本时挺省心的。目录里有软链接的话,行为会比 os.walk() 更容易先想清楚。