【发布时间】:2022-10-05 04:28:49
【问题描述】:
我有一个包裹,就像
mypkg
|-mypkg
|- data
|- data.csv
|- __init__.py # Required for importlib.resources
|- scripts
|- module.py
|- __init__.py
模块module.py 需要data.csv 来执行某个任务。
我用来访问data.csv 的第一个天真的方法是
# module.py - Approach 1
from pathlib import Path
data_path = Path(Path.cwd().parent, 'data', 'data.csv')
但是当我们通过from mypkg.scripts import module 或类似方法导入module.py 时,这显然会中断。无论mypkg 是从哪里导入的,我都需要一种访问data.csv 的方法。
下一个简单的方法是使用__file__ 属性来访问module.py 模块所在的路径。
# module.py - Approach 2
from pathlib import Path
data_path = Path(Path(__file__).resolve().parents[1], 'data', 'data.csv')
但是,在研究这个问题时,我发现不鼓励这种方法。例如,参见How to read a (static) file from inside a Python package?。
尽管对于这个问题的最佳解决方案似乎没有完全一致,但看起来importlib.resources 可能是最受欢迎的。我相信这看起来像:
# module.py - Approach 3
from pathlib import Path
import importlib.resources
data_path_resource = importlib.resources('mypkg.data', 'data.csv')
with data_path_resources as resource:
data_path = resource
为什么这个最终方法比__file__ 更好?如果源代码被压缩,似乎__file__ 将不起作用。这是我不熟悉的情况,听起来也有点边缘化。我认为我的代码永远不会被压缩运行..
importlib 增加的开销似乎有点荒谬。我需要在数据文件夹中添加一个空的__init__.py,我需要导入importlib,并且我需要使用上下文管理器来访问相对路径。
我对importlib 策略的好处缺少什么?为什么不直接使用__file__?
编辑:importlib 方法的一个可能理由是它稍微改进了语义。那就是data.csv 应该被认为是包的一部分,所以我们应该使用类似from mypkg import data.csv 的东西来访问它,当然这种语法只适用于导入.py python 模块。但是importlib.resources 有点将“从某个包导入某些内容”语义移植到更通用的文件类型。
相比之下,从__file__ 构建相对路径的语法有点像:这个模块在文件结构中很接近数据文件,所以让我们利用它来访问它。数据文件是包的一部分这一事实没有被利用。
【问题讨论】:
-
你读过wim's answer吗?这是按“趋势(最近的投票数更多)”排序的最佳答案。它讨论了为什么不使用您提到的任何一个。对于 Python 3.9+,它建议使用
pkgutil和importlib_resources。