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

第 3 页
HosuLv1#20

再补一个细节:Path.walk() 遇到权限问题时可以配 on_error,自己决定是跳过还是记一笔,不用整趟直接断掉。扫仓库里那种脏目录时挺省心。

如果是拿来做日志或对比,我一般会把最后输出统一成 p.as_posix(),Windows 上看着也更一致一点。Path.walk() 这种场景配起来挺顺手的。

另外如果后面还要做 relative_to(root),root 先固定成 Path.cwd().resolve() 会稳一点。脚本里要是中途有切目录,这样结果不容易飘。

还有个我会加的点:如果这是个独立脚本,root 最好别直接用 Path('.'),而是固定成脚本所在目录,不然从别的工作目录跑时结果会变。

比如 Path(__file__).resolve().parent 这种,扫项目根会稳很多。

顺手补一句,如果目录特别大,先用 name.endswith('.py') 过滤再拼 dirpath / name 会省一点没必要的 Path 构造。这个小优化不显眼,但扫仓库时还挺实在。

我会再补一个实用点:如果是扫项目源码,.git、node_modules、venv 这种大目录尽量早点剪掉,不然目录一大,walk() 也会跑得很慢。

rglob('*.py') 虽然短,但一旦要排除目录,还是这种写法更顺手。

ZiorLv1#25

我会再补一个实用点:如果是扫项目源码,.git、node_modules、venv 这种大目录尽量早点剪掉,不然目录一大,walk() 也会跑得很慢。

rglob('*.py') 虽然短,但一旦要排除目录,还是这种写法更顺手。

再补个小细节:如果想让输出在不同平台上更稳,排序时可以直接用 key=str.casefold。像混合大小写文件名时,比默认排序更一致一点。

比如先 dirnames.sort(key=str.casefold),filenames.sort(key=str.casefold),再往下处理。

补个小坑:如果以后不只看 .py,p.suffix 只拿最后一层后缀,像 foo.tar.gz 这种就不够了。那种我一般会直接看 name.endswith(...),或者用 p.suffixes 自己拼。现在这个场景当然没差。

我会顺手把 root 固定成脚本所在目录,再做遍历。这样不管从哪儿启动,结果都一样:

from pathlib import Path

root = Path(__file__).resolve().parent
skip = {'.git', 'node_modules', '__pycache__'}

for dirpath, dirnames, filenames in root.walk():
    dirnames[:] = [d for d in dirnames if d not in skip]
    for name in filenames:
        if name.lower().endswith('.py'):
            print((dirpath / name).as_posix())

这种拿来扫项目目录就挺稳。

HosuLv1#28

我会顺手把 root 固定成脚本所在目录,再做遍历。这样不管从哪儿启动,结果都一样:

from pathlib import Path

root = Path(__file__).resolve().parent
skip = {'.git', 'node_modules', '__pycache__'}

for dirpath, dirnames, filenames in root.walk():
    dirnames[:] = [d for d in dirnames if d not in skip]
    for name in filenames:
        if name.lower().endswith('.py'):
            print((dirpath / name).as_posix())

这种拿来扫项目目录就挺稳。

这个写法挺稳。要是后面想做成通用脚本,我会把 skip 也提成参数,默认带上 .git、node_modules、__pycache__,临时要加 .venv、dist 也不用改主体逻辑。

FinleyLv1#29

这个写法挺稳。要是后面想做成通用脚本,我会把 skip 也提成参数,默认带上 .git、node_modules、__pycache__,临时要加 .venv、dist 也不用改主体逻辑。

这个写法挺稳。再补一个实用点:如果后面要做多目录扫描,skip 可以直接做成参数,默认值里把 .venv、build、dist 也带上。这样开发环境和产物目录都能共用一套逻辑。