应使用 importlib.resources.files()(3.9+)或 open_text()/open_binary()(3.7–3.8),禁用已弃用的 read_text() 和 contents();因其依赖 file 路径拼接,在 zip 包、命名空间包或符号链接下会静默失败或抛 FileNotFoundError。

直接用 importlib.resources.files()(Python 3.9+)或 importlib.resources.open_binary()/open_text()(3.7–3.8),别碰已弃用的 importlib.resources.read_text() 和 contents() —— 它们在包含命名空间包或符号链接时会静默失败或抛 FileNotFoundError。
为什么 importlib.resources.read_text() 不安全?
这个函数在 Python 3.9 被标记为 deprecated,核心问题是它内部依赖 __file__ 和文件系统路径拼接。当包被 zipimport 加载(如打包成 .whl 或 pyz)、位于命名空间包中、或资源实际是 symlink 指向外部路径时,read_text() 会直接报 FileNotFoundError,且不提供 fallback 机制。
- 常见错误现象:
FileNotFoundError: [Errno 2] No such file or directory: '/path/to/pkg/data/config.json',但资源明明存在 - 使用场景:CI/CD 构建后部署到容器、PyInstaller 打包、PEP 420 命名空间包
- 替代方案必须基于
Traversable接口(返回对象支持.joinpath()、.is_file()、.open())
importlib.resources.files() 是唯一推荐入口(3.9+)
它返回一个 Traversable 对象,代表包的根目录,所有操作都通过该对象进行,与底层加载机制无关(zip、filesystem、namespace 全兼容)。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 读取文本:
importlib.resources.files('mypkg').joinpath('data', 'config.json').read_text(encoding='utf-8') - 读取二进制:
importlib.resources.files('mypkg').joinpath('static', 'logo.png').read_bytes() - 检查存在性:
res = importlib.resources.files('mypkg').joinpath('templates'); res.is_file() or res.is_dir() - 注意:路径分隔符统一用
/(joinpath()自动处理),不要用os.path.join()
兼容旧版本(3.7–3.8)必须用 open_text() + files() 回退
Python 3.7–3.8 没有 files(),但已有 open_text() 和 open_binary(),它们比 read_text() 更健壮(内部已尝试 Traversable fallback)。不过仍需手动处理异常并降级到 importlib_resources backport(非标准库)。
- 优先尝试标准库:
from importlib import resources; resources.open_text('mypkg', 'data/config.json') - 若报
AttributeError(3.7 早期版),则安装 backport:pip install importlib-resources,再用importlib_resources.files() - 绝对不要在 3.7+ 中继续用
resources.contents()—— 它只返回文件名列表,不保证可访问,且对 zip 包返回空 - 性能影响:相比直接读文件,
files().joinpath().read_text()多一次对象构造,但差异在纳秒级,可忽略
容易被忽略的路径和编码陷阱
资源路径是相对于包根目录的纯字符串,不是模块路径;编码必须显式指定,否则 read_text() 在非 UTF-8 系统上可能解码失败。
-
files('mypkg.subpkg').joinpath('data.txt')→ 错!files()只接受顶层包名,子包要写成files('mypkg').joinpath('subpkg', 'data.txt') - 二进制资源(如图片、字体)必须用
read_bytes()或open_binary(),用read_text()会抛UnicodeDecodeError - JSON/YAML 配置建议统一用 UTF-8 并显式传
encoding='utf-8',避免依赖 locale - Windows 上路径大小写不敏感,但 Linux/macOS 敏感——测试务必在目标部署环境运行
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










