pathlib模块 — 面向对象文件路径

Python标准库精讲专题 · 文件与目录处理篇 · 掌握面向对象路径操作

专题:Python标准库精讲系统学习

关键词:Python, 标准库, pathlib, Path, PurePath, 文件路径, 目录操作, 文件操作, os.path

一、pathlib模块概述

pathlib是Python 3.4版本引入的面向对象文件路径操作模块,旨在提供一个更加直观、可读性更强的路径操作接口。与传统的os.path模块相比,pathlib将路径抽象为对象,通过方法调用和运算符重载完成路径操作,代码更加简洁优雅。

pathlib的核心设计理念是将文件系统路径视为"对象"而非"字符串"。这意味着路径拼接、分解、比较等操作不再依赖字符串处理函数,而是通过对象方法和运算符来完成,大大减少了字符串解析带来的错误风险。

与os.path的对比

操作类型 os.path方式 pathlib方式
路径拼接 os.path.join(dir, file) Path(dir) / file
获取文件名 os.path.basename(path) Path(path).name
获取父目录 os.path.dirname(path) Path(path).parent
判断是否存在 os.path.exists(path) Path(path).exists()
遍历目录 os.listdir(dir) Path(dir).iterdir()

pathlib的两大核心类是PurePath(纯路径处理)和Path(具体路径操作)。PurePath只做路径的解析和运算,不涉及实际的I/O操作;Path继承PurePath并增加了所有与文件系统交互的方法。这种分离设计使得PurePath可以在没有文件系统的场景下安全使用(如URL路径处理)。

核心优势:面向对象设计替代字符串拼接、运算符/重载实现直观路径组合、统一的文件操作API、跨平台路径自动适配、与os.path兼容且用法更现代。

# pathlib vs os.path 对比示例 from pathlib import Path import os.path # 传统方式 path1 = os.path.join("/home/user", "docs", "readme.txt") base = os.path.basename(path1) # "readme.txt" ext = os.path.splitext(path1)[1] # ".txt" # pathlib方式 p = Path("/home/user") / "docs" / "readme.txt" base = p.name # "readme.txt" ext = p.suffix # ".txt" print(f"pathlib方式更直观: {p}") print(f"传统方式结果: {path1}")

二、PurePath纯路径处理

PurePath是pathlib中的路径解析基类,只进行纯字符串层面的路径操作,不访问实际文件系统。它有两个具体子类:PurePosixPath(POSIX风格路径,如Linux/macOS)和PureWindowsPath(Windows风格路径)。

PurePath的自动适配与显式使用

当直接使用PurePath()构造时,会自动适配当前操作系统的路径格式。如果需要跨平台路径分析(如在Windows上分析Linux路径),则应显式使用PurePosixPath或PureWindowsPath。

# PurePath基本用法 from pathlib import PurePath, PurePosixPath, PureWindowsPath # 自动适应当前系统 p = PurePath("/home/user/docs/file.txt") print(p) # PurePosixPath('/home/user/docs/file.txt') 在Linux上 # 显式指定路径风格 posix_p = PurePosixPath("/home/user/docs/file.txt") win_p = PureWindowsPath("C:\\Users\\Admin\\docs\\file.txt") print(posix_p) print(win_p)

路径拼接与运算符/

pathlib使用/运算符实现路径拼接,这是最引人注目的特性之一。左操作数必须是PurePath(或Path)对象,右操作数可以是字符串或另一个Path对象。多个路径段可以链式拼接。

# 路径拼接示例 from pathlib import PurePosixPath base = PurePosixPath("/home/user") # 单个段拼接 docs = base / "docs" # 链式拼接 full = base / "docs" / "python" / "notes.txt" print(full) # PurePosixPath('/home/user/docs/python/notes.txt') # 右操作数也可以是Path对象 sub = PurePosixPath("projects") result = base / sub / "src/main.py" print(result) # PurePosixPath('/home/user/projects/src/main.py') # 斜杠开头的字符串会重置路径 p2 = PurePosixPath("user") / "/etc" / "config" print(p2) # PurePosixPath('/etc/config') — 注意/user被丢弃了

路径分解属性

PurePath提供了一系列属性来分解路径的各个组成部分,理解这些属性对于精准的路径操作非常重要。

属性说明示例结果
drive盘符(Windows)或空'C:' / ''
root根目录标记'\\' / '/'
anchordrive + root'C:\\' / '/'
parts逐级拆分的元组('/', 'home', 'user', 'docs')
parent直接父路径PurePosixPath('/home/user')
parents所有父路径的可迭代对象[PurePosixPath('/home'), ...]
name末尾文件名/目录名'file.txt'
stem不含后缀的文件名'file'
suffix扩展名(含点)'.txt'
suffixes所有扩展名列表['.tar', '.gz']
# 路径分解实战 from pathlib import PurePosixPath p = PurePosixPath("/home/user/docs/python/notes.txt") print(f"完整路径: {p}") print(f"drive: {p.drive!r}") # ''(POSIX无盘符概念) print(f"root: {p.root!r}") # '/' print(f"anchor: {p.anchor!r}") # '/' print(f"parts: {p.parts}") # ('/', 'home', 'user', 'docs', 'python', 'notes.txt') print(f"parent: {p.parent}") # /home/user/docs/python print(f"name: {p.name}") # notes.txt print(f"stem: {p.stem}") # notes print(f"suffix: {p.suffix}") # .txt # parents — 逐级上溯 for i, parent in enumerate(p.parents): print(f"parents[{i}]: {parent}") # parents[0]: /home/user/docs/python # parents[1]: /home/user/docs # parents[2]: /home/user # parents[3]: /home # parents[4]: / # 多后缀文件 tgz = PurePosixPath("archive.tar.gz") print(tgz.suffix) # .gz print(tgz.suffixes) # ['.tar', '.gz'] print(tgz.stem) # archive.tar

特别注意:PurePath不接触文件系统,因此exists()、is_dir()、is_file()等方法在PurePath上不可用——这些是在Path类中实现的。如果只需要解析和操作路径字符串(如URL、配置文件中的路径),应优先使用PurePath以获得更好的性能和安全性。

三、Path核心类

Path继承了PurePath的全部功能,并增加了所有涉及实际文件系统交互的方法。它是日常开发中使用最多的类,封装了文件测试、目录遍历、元信息查询等操作。

构造常用路径

Path提供了多个类方法来快速获取系统级和用户相关的重要路径,大幅简化了路径定位的代码量。

# Path的构造与常用类方法 from pathlib import Path # 基于当前工作目录 p1 = Path(".") # 当前目录 p2 = Path("docs/readme.txt") # 绝对路径 p3 = Path("/usr/local/bin") p4 = Path.home() # 用户家目录, 如 /home/user 或 C:\Users\xxx p5 = Path.cwd() # 当前工作目录 print(f"家目录: {p4}") print(f"当前目录: {p5}") # 混合构造 config = Path.home() / ".config" / "myapp" / "config.json" print(f"配置文件路径: {config}")

文件系统查询

Path提供了丰富的文件系统状态查询方法,用于判断路径类型、获取元信息和测试文件状态,是编写健壮文件操作代码的基础。

# 文件状态查询 from pathlib import Path import time p = Path("/etc/hostname") # 存在性检查 print(f"是否存在: {p.exists()}") # 类型判断 print(f"是目录吗: {p.is_dir()}") print(f"是文件吗: {p.is_file()}") print(f"是符号链接: {p.is_symlink()}") print(f"是绝对路径: {p.is_absolute()}") # 文件元信息 (stat) if p.exists(): stat_info = p.stat() print(f"文件大小: {stat_info.st_size} bytes") print(f"最后修改: {time.ctime(stat_info.st_mtime)}") print(f"权限模式: {oct(stat_info.st_mode)}") print(f"inode: {stat_info.st_ino}")

目录遍历与文件筛选

Path的目录遍历功能非常强大,尤其是glob模式匹配,可以快速筛选出符合特定模式的文件和目录。itertools风格链式调用让复杂筛选变得简单。

# 目录遍历 from pathlib import Path data_dir = Path("data") # iterdir() — 遍历直接子项(非递归) if data_dir.exists(): for entry in data_dir.iterdir(): kind = "目录" if entry.is_dir() else "文件" print(f"[{kind}] {entry.name}") # glob() — 模式匹配(非递归) for py_file in Path("src").glob("*.py"): print(f"Python文件: {py_file}") # rglob() — 递归全匹配 for all_py in Path("project").rglob("**/*.py"): print(f"找到: {all_py}") # 注意: rglob("*.py") 等价于 glob("**/*.py") for test_file in Path("tests").rglob("test_*.py"): print(f"测试文件: {test_file}") # 组合筛选 img_dir = Path("assets") images = [f for f in img_dir.rglob("*") if f.suffix.lower() in (".png", ".jpg", ".jpeg", ".gif")] print(f"找到 {len(images)} 个图片文件")

性能提示:glob模式比手动os.listdir+fnmatch高效且简洁。对于需要递归搜索的场景,rglob()是最佳选择。如果同时需要文件元信息(大小、修改时间),建议使用Path.stat()而非多次访问文件系统。

四、路径操作

Path类提供了完整的目录和文件操作功能,包括创建、删除、重命名和链接操作。这些方法通常会引发OSError或FileNotFoundError等异常,建议在调用时做好异常处理。

目录创建与删除

mkdir用于创建目录,rmdir用于删除空目录。mkdir的parents和exist_ok参数提供了类似mkdir -p的行为,大幅简化了多级目录创建逻辑。

# 目录操作 from pathlib import Path # 创建单级目录 Path("temp").mkdir(exist_ok=True) # 创建多级目录 (类似 mkdir -p) Path("project/src/main/java/com/example").mkdir(parents=True, exist_ok=True) # 删除空目录 Path("temp").rmdir() # 目录必须为空,否则抛出OSError # 删除目录树(需要shutil配合) import shutil shutil.rmtree("project") # 递归删除非空目录

文件重命名与替换

rename直接重命名文件或目录,replace则会在目标已存在时强制覆盖,避免了跨设备操作时的复杂性。

# 文件重命名与替换 from pathlib import Path # 重命名(同设备内移动) Path("temp.txt").rename("temp_backup.txt") # 跨设备移动(Python 3.8+) # Path("source.txt").rename("/tmp/source.txt") # 可能跨设备 # replace — 替换目标文件(无论是否存在) Path("new_version.txt").replace("production.txt") # 安全重命名(先检查目标是否存在) def safe_rename(src: Path, dst: Path): if dst.exists(): backup = dst.with_suffix(dst.suffix + ".bak") dst.rename(backup) print(f"已备份旧文件为: {backup}") src.rename(dst) safe_rename(Path("draft.txt"), Path("final.txt"))

删除与链接

unlink用于删除文件,symlink_to和hardlink_to分别创建符号链接和硬链接。链接操作在跨平台时需要特别注意——Windows上可能需要管理员权限。

# 文件删除与链接 from pathlib import Path # 删除文件 file = Path("temp_backup.txt") if file.exists(): file.unlink() # 删除文件,missing_ok=True可抑制FileNotFoundError # Python 3.8+: file.unlink(missing_ok=True) # 创建符号链接 target = Path("/usr/local/bin/python3") link = Path("~/mypython").expanduser() # link.symlink_to(target) # 需要合适权限 # 创建硬链接 original = Path("important.txt") hardlink = Path("important_backup.txt") if original.exists(): # hardlink.hardlink_to(original) # Windows上可能需要管理员权限 print(f"将为 {original} 创建硬链接") # with_name / with_suffix — 派生新路径而不访问磁盘 p = Path("data/report_2024.csv") print(p.with_name("report_2025.csv")) # data/report_2025.csv print(p.with_suffix(".json")) # data/report_2024.json

安全实践:在进行文件删除/移动操作前,先检查文件是否存在,或使用Pyhhon 3.8+的missing_ok参数。rename和replace操作在Windows上如果目标已存在可能会失败,建议先unlink再rename,或使用replace方法。

五、文件读写

Path内置了简洁的文件读写方法,支持纯文本和二进制模式的读写操作,无需手动管理文件打开和关闭。对于简单的文件读写场景,这些方法比内置的open()更加便捷。

文本文件读写

read_text一次性读取整个文本文件的内容并返回字符串;write_text将字符串写入文件。这两个方法会自动处理文件的打开和关闭,适合中等规模的文件读写。

# 文本文件读写 from pathlib import Path file = Path("notes.txt") # 写入文本(覆盖模式) file.write_text("这是第一行\n") file.write_text("这是第二行\n") # 注意:会覆盖上一行! # 追加写入 with file.open("a") as f: f.write("这是追加的行\n") # 读取全部文本 content = file.read_text(encoding="utf-8") print(content) # 逐行处理 for line in file.read_text().splitlines(): if line.strip(): print(f">> {line.strip()}")

二进制文件读写

read_bytes和write_bytes用于处理二进制文件,如图像、音频、压缩包等。它们以字节串(bytes)的形式操作数据,适用于任何非文本文件。

# 二进制文件读写 from pathlib import Path # 写入二进制数据 data = b"\x89PNG\r\n\x1a\n" # PNG文件头 Path("icon.png").write_bytes(data) # 读取二进制数据 img_data = Path("icon.png").read_bytes() print(f"读取了 {len(img_data)} 字节") print(f"前8个字节: {img_data[:8].hex()}") # 复制文件(用二进制方式) src = Path("source.docx") dst = Path("backup.docx") if src.exists(): dst.write_bytes(src.read_bytes()) print(f"已复制到 {dst}")

open()上下文管理器

对于需要精细控制(如指定编码、逐行处理、大文件分块读取)的场景,Path.open()提供了与内置open()相同的功能,但以方法调用的方式集成在Path对象上。

# 使用Path.open()上下文管理器 from pathlib import Path log = Path("server.log") # 逐行读取大文件(推荐方式) with log.open("r", encoding="utf-8") as f: for line in f: if "ERROR" in line: print(f"错误日志: {line.strip()}") # 二进制模式打开 with Path("data.bin").open("rb") as f: header = f.read(32) print(f"文件头: {header.hex()}") # 追加模式 with Path("access.log").open("a") as f: import datetime f.write(f"[{datetime.datetime.now()}] 访问记录\n") # 文件锁配合(需额外库) # with fasteners.InterProcessLock(Path("data.lock")): # with Path("shared.json").open("r+") as f: # data = json.load(f) # data["counter"] = data.get("counter", 0) + 1 # f.seek(0) # json.dump(data, f)

注意事项:read_text()和read_bytes()会将整个文件加载到内存中,不适合大文件(如数GB的日志)。对于大文件,应使用Path.open()配合for循环逐行处理。write_text()和write_bytes()是覆盖写入,如需追加应使用open("a")模式。

六、路径解析与转换

Path提供了丰富的路径解析和格式转换方法,用于将相对路径解析为绝对路径、计算相对路径、生成URI以及在不同路径风格之间转换。

resolve与absolute — 获取绝对路径

resolve解析符号链接并返回规范化的绝对路径;absolute仅将相对路径转换为绝对路径,不解析符号链接。理解两者的区别对于正确处理路径十分关键。

# 路径解析 from pathlib import Path # resolve() — 消解.和..并解析符号链接 rel = Path("../docs/./notes.txt") abs_path = rel.resolve() print(f"相对路径: {rel}") print(f"解析后: {abs_path}") # absolute() — Python 3.11+ 仅转绝对路径,不解析符号链接 cur = Path(".") if hasattr(cur, "absolute"): print(f"当前绝对路径: {cur.absolute()}") else: print(f"回退方案: {cur.resolve()}")

relative_to — 计算相对路径

relative_to计算从某个基准路径到当前路径的相对路径表示,常用于需要在不同目录结构之间表达路径关系的场景。

# relative_to — 计算相对路径 from pathlib import Path base = Path("/home/user/project/src") target = Path("/home/user/project/src/utils/helper.py") # 计算从base到target的相对路径 rel = target.relative_to(base) print(rel) # PurePosixPath('utils/helper.py') # 带基准目录部分匹配 # rel = target.relative_to("/home/user/project") # print(rel) # src/utils/helper.py # 如果路径不匹配会抛出ValueError try: target.relative_to("/var/log") except ValueError as e: print(f"路径不匹配: {e}") # Python 3.12+ — walk_up参数允许沿目录树向上 # try: # rel_up = target.relative_to("/home/user/project/shared", walk_up=True) # print(rel_up) # '../src/utils/helper.py' # except ValueError: # pass

URI与POSIX风格转换

as_uri将文件路径转换为file:// URI格式(需绝对路径),这在Web开发中非常实用。as_posix将路径中的反斜杠统一转换为正斜杠,便于跨平台序列化。

# URI与格式转换 from pathlib import Path from pathlib import PureWindowsPath # as_uri — 生成file:// URI abs_path = Path("/home/user/docs/report.pdf") uri = abs_path.as_uri() print(uri) # file:///home/user/docs/report.pdf # Windows路径转URI # win = PureWindowsPath("C:\\Users\\Admin\\report.pdf") # print(win.as_uri()) # file:///C:/Users/Admin/report.pdf # as_posix — 统一使用正斜杠 # win_path = PureWindowsPath("C:\\Users\\Admin") # print(win_path.as_posix()) # C:/Users/Admin # 路径比较 p1 = Path("/home/user/docs") p2 = Path("/home/user/docs") print(f"路径相等: {p1 == p2}") # True # 判断子路径 config = Path("/etc/nginx/nginx.conf") etc = Path("/etc") try: config.relative_to(etc) print(f"{config} 在 {etc} 之下") except ValueError: print(f"不在同一路径下")

注意:relative_to要求目标路径必须是当前路径的前缀(包含关系),否则抛出ValueError。Python 3.12新增的walk_up参数支持生成包含..的相对路径。as_uri要求路径必须是绝对路径。

七、实战应用

将pathlib应用于实际开发场景可以大幅提升代码质量和开发效率。以下是几个高频实战场景的完整代码示例。

场景一:批量文件重命名

批量修改文件名(如统一添加前缀/后缀、替换特定字符、修改扩展名)是文件处理中最常见的需求。结合Path的iterdir/glob和with_stem/with_suffix方法,可以写出简洁的重命名逻辑。

# 批量重命名:给所有图片添加日期前缀 from pathlib import Path import datetime today = datetime.date.today().strftime("%Y%m%d") img_dir = Path("gallery") # 安全重命名函数 def batch_rename(directory: Path, pattern: str, prefix: str = ""): """为匹配pattern的文件添加prefix前缀""" renamed = 0 for f in directory.glob(pattern): new_name = f"{prefix}{f.stem}{f.suffix}" new_path = f.with_name(new_name) if not new_path.exists(): f.rename(new_path) renamed += 1 print(f"重命名: {f.name} → {new_name}") else: print(f"跳过: {new_path.name} 已存在") return renamed if img_dir.exists(): count = batch_rename(img_dir, "*.jpg", f"{today}_") print(f"已重命名 {count} 个文件") # 替换文件名中的空格 def replace_spaces(directory: Path, replacement: str = "_"): for f in directory.rglob("*"): if f.is_file() and " " in f.stem: new_name = f"{f.stem.replace(' ', replacement)}{f.suffix}" f.rename(f.with_name(new_name)) replace_spaces(Path("documents"), "_")

场景二:目录树遍历与统计

遍历目录树获取文件类型分布、总大小、最新修改时间等统计信息,是自动化监控和报告生成的基础。

# 目录树统计分析 from pathlib import Path from collections import defaultdict import datetime def analyze_directory(root: Path): """分析目录结构,返回统计信息""" stats = { "total_files": 0, "total_dirs": 0, "total_size": 0, "by_extension": defaultdict(int), "by_size_range": defaultdict(int), "largest_files": [], "newest_files": [], } for entry in root.rglob("*"): if entry.is_dir(): stats["total_dirs"] += 1 elif entry.is_file(): stats["total_files"] += 1 size = entry.stat().st_size stats["total_size"] += size # 按扩展名分类 ext = entry.suffix.lower() or "(无扩展名)" stats["by_extension"][ext] += 1 # 按大小范围分类 if size < 1024: stats["by_size_range"]["<1KB"] += 1 elif size < 1024 * 1024: stats["by_size_range"]["1KB-1MB"] += 1 else: stats["by_size_range"][">1MB"] += 1 # 记录最大文件 stats["largest_files"].append((size, entry)) stats["newest_files"].append((entry.stat().st_mtime, entry)) # 排序 stats["largest_files"].sort(reverse=True, key=lambda x: x[0]) stats["newest_files"].sort(reverse=True, key=lambda x: x[0]) return stats # 使用示例 project = Path("project") if project.exists(): info = analyze_directory(project) print(f"文件总数: {info['total_files']}") print(f"目录总数: {info['total_dirs']}") print(f"总大小: {info['total_size'] / 1024 / 1024:.2f} MB") print(f"按扩展名统计: {dict(info['by_extension'])}") if info["largest_files"]: size, f = info["largest_files"][0] print(f"最大文件: {f} ({size / 1024:.1f} KB)") if info["newest_files"]: mtime, f = info["newest_files"][0] dt = datetime.datetime.fromtimestamp(mtime) print(f"最新修改: {f} ({dt})")

场景三:文件类型筛选与分类整理

根据文件类型自动分类整理到不同目录,是文件管理的常用场景。结合suffix属性、shutil.move和异常处理,可以构建健壮的文件整理工具。

# 文件类型筛选与自动分类 from pathlib import Path import shutil # 按类别整理文件 FILE_CATEGORIES = { "images": [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".svg", ".webp"], "documents": [".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt", ".md"], "archives": [".zip", ".tar", ".gz", ".bz2", ".7z", ".rar"], "code": [".py", ".js", ".ts", ".java", ".cpp", ".h", ".css", ".html", ".json", ".yaml"], "videos": [".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv"], } def organize_files(download_dir: Path): """将下载目录中的文件按类型整理到子目录""" if not download_dir.exists(): print(f"目录不存在: {download_dir}") return for f in download_dir.iterdir(): if not f.is_file(): continue # 判断文件类别 target_category = "others" for category, extensions in FILE_CATEGORIES.items(): if f.suffix.lower() in extensions: target_category = category break # 创建分类目录并移动文件 target_dir = download_dir / target_category target_dir.mkdir(exist_ok=True) target_path = target_dir / f.name if not target_path.exists(): shutil.move(str(f), str(target_path)) print(f"移动: {f.name} → {target_category}/") else: print(f"跳过: {f.name} (目标已存在)") # 统计结果 for category in list(FILE_CATEGORIES.keys()) + ["others"]: cat_dir = download_dir / category if cat_dir.exists(): count = len(list(cat_dir.iterdir())) print(f" {category}: {count} 个文件") # 使用 # organize_files(Path.home() / "Downloads")

生产环境建议:使用pathlib重写遗留的os.path代码。在实际项目中,pathlib代码的平均行数比os.path版本少30%-50%,可读性显著提升。结合类型注解(如Path -> Path类型提示),还能获得IDE的自动补全和类型检查支持。

八、核心总结

pathlib模块是Python面向对象路径操作的里程碑式设计,它从根本上改变了Python开发者操作文件系统的方式。

核心要点:

1. PurePath系列:纯路径解析,不访问文件系统,适合路径字符串运算和跨平台分析。

2. Path系列:继承PurePath,集成所有文件I/O操作,是日常开发的主力类。

3. /运算符:路径拼接更直观,链式语法简洁优雅。

4. 路径分解属性:parts/parent/name/stem/suffix一次性获取路径所有组成部分,无需手动解析字符串。

5. glob/rglob:模式化文件搜索,比手动递归遍历更高效。

6. 内置读写方法:read_text/write_text等简化小文件读写,open()上下文管理器支持大文件逐行处理。

7. 跨平台兼容:自动适应当前操作系统路径格式,无需编写条件判断代码。

8. 不替代os.path所有功能:某些底层操作(如chmod、chown)仍需使用os模块,但日常路径操作应优先选择pathlib。

# 快速参考 — 常用pathlib代码片段 from pathlib import Path # 列出当前目录所有Python文件 [ str(f) for f in Path(".").glob("*.py") ] # 递归删除空目录 [ d.rmdir() for d in Path(".").rglob("*") if d.is_dir() and not list(d.iterdir()) ] # 安全读取文件(不存在时返回默认值) def safe_read(path: Path, default: str = "") -> str: return path.read_text(encoding="utf-8") if path.exists() else default # 确保目录存在 Path("output/images").mkdir(parents=True, exist_ok=True) # 文件重命名并保持扩展名 Path("data.csv").with_stem("data_backup") # → data_backup.csv # 获取精简文件树(可打印) def tree(dir: Path, prefix: str = ""): for child in sorted(dir.iterdir()): yield f"{prefix}├── {child.name}" if child.is_dir(): yield from tree(child, prefix + "│ ") print("\n".join(tree(Path("src"))))

总体而言,pathlib不仅仅是os.path的"替代品",它代表了Python文件路径处理从"函数式"到"面向对象"的范式转变。在新项目中应优先使用pathlib,在维护旧代码时也可以逐步迁移,享受面向对象路径操作带来的便利性和代码质量的提升。