如何通过模块相对路径读取文件?求更优雅实现方案
解决模块内数据文件的优雅读取问题
先还原你的场景:
你的目录结构如下:
├--- mod | ├--- __init__.py | └--- abc.data └--- test.py
原本__init__.py里用相对路径读取文件:
with open("abc.data", 'r') as f: pass # read and process the data
而test.py仅做模块导入:
import mod
运行时触发FileNotFoundError,核心原因是Python解释器的当前工作目录是test.py的父目录,而非mod模块所在目录,导致找不到目标数据文件。
你已经找到一种可行方案,但觉得处理大量文件时不够优雅,下面给你几个更简洁易维护的思路:
方案1:用pathlib实现面向对象的路径处理(Python 3.4+推荐)
pathlib是Python 3.4引入的现代化路径库,比传统os.path更直观,尤其适合批量处理文件:
修改mod/__init__.py:
from pathlib import Path # 获取当前模块所在目录的路径 module_dir = Path(__file__).parent # 直接拼接数据文件路径(支持链式写法) data_file = module_dir / "abc.data" with open(data_file, 'r') as f: pass # 处理数据
如果要读取多个数据文件,代码会更简洁:
from pathlib import Path module_dir = Path(__file__).parent data_filenames = ["abc.data", "def.data", "ghi.data"] for filename in data_filenames: file_path = module_dir / filename with open(file_path, 'r') as f: pass # 逐个处理文件
方案2:封装复用工具函数
如果模块内需要频繁读取内部数据文件,可以封装一个工具函数,避免重复编写路径拼接逻辑:
from pathlib import Path def get_module_data_path(filename): """获取模块内数据文件的绝对路径""" return Path(__file__).parent / filename # 使用示例 with open(get_module_data_path("abc.data"), 'r') as f: pass with open(get_module_data_path("def.data"), 'r') as f: pass
这种方式让代码更整洁,后续维护也更方便。
方案3:用importlib.resources处理包内资源(Python 3.7+)
如果你的模块是需要打包发布的正式项目,importlib.resources是更规范的选择——它会自动处理包安装后的资源路径,无需关心文件系统的具体位置:
from importlib.resources import read_text # 直接读取文件内容,无需手动管理文件句柄 content = read_text("mod", "abc.data") # 处理读取到的内容即可
若需要操作文件对象(比如处理大文件或二进制文件),可以用open_text或open_binary:
from importlib.resources import open_text with open_text("mod", "abc.data") as f: pass # 处理文件
方案选择建议
- 小型脚本/模块:优先选
pathlib,简洁直观; - 需频繁读取多文件:封装工具函数提升复用性;
- 可安装的正式包:用
importlib.resources更规范。
内容的提问来源于stack exchange,提问作者kqwyf




