TLDR;使用标准库importlib.resources module
如果你不关心向后兼容性
from importlib import resources as impresources
from . import templates
inp_file = (impresources.files(templates) / 'temp_file')
with inp_file.open("rt") as f:
template = f.read()
Details
The 传统的 pkg_resources from setuptools不再推荐,因为新方法:
- it is 性能显着提高;
- 这是更安全的,因为使用包(而不是路径字符串)会引发编译时错误;
- 它更直观,因为您不必“连接”路径;
- 仅依赖于 Python 的标准库(没有额外的 3rdp 依赖项
setuptools
).
我保留了传统的首先列出,以解释在移植现有代码时与新方法的差异(也移植)在这里解释).
假设您的模板位于模块包内嵌套的文件夹中:
<your-package>
+--<module-asking-the-file>
+--templates/
+--temp_file <-- We want this file.
Note 1:当然,我们不应该摆弄__file__
属性(例如,当从 zip 中提供代码时,代码将会中断)。
Note 2:如果您正在构建此包,请记住将您的数据文件声明为package_data or data_files在你的setup.py
.
1)使用pkg_resources
from setuptools
(slow)
您可以使用pkg_resources包裹来自设置工具分布,但是这是有代价的,性能方面:
import pkg_resources
# Could be any dot-separated package/module name or a "Requirement"
resource_package = __name__
resource_path = '/'.join(('templates', 'temp_file')) # Do not use os.path.join()
template = pkg_resources.resource_string(resource_package, resource_path)
# or for a file-like stream:
template = pkg_resources.resource_stream(resource_package, resource_path)
Tips:
...并注意根据Setuptools/pkg_resources
文档,你不应该使用os.path.join
:
基本资源访问
请注意,资源名称必须是/
- 分隔的路径并且不能是绝对的(即没有前导/
) 或包含相对名称,例如“..
". Do not use os.path
按原样操作资源路径的例程not文件系统路径。
2) Python >= 3.7,或使用向后移植的importlib_resources library
使用标准库的importlib.resources module这比更有效setuptools
, above:
try:
from importlib import resources as impresources
except ImportError:
# Try backported to PY<37 `importlib_resources`.
import importlib_resources as impresources
from . import templates # relative-import the *package* containing the templates
try:
inp_file = (impresources.files(templates) / 'temp_file')
with inp_file.open("rb") as f: # or "rt" as text file with universal newlines
template = f.read()
except AttributeError:
# Python < PY3.9, fall back to method deprecated in PY3.11.
template = impresources.read_text(templates, 'temp_file')
# or for a file-like stream:
template = impresources.open_text(templates, 'temp_file')
注意力:
关于功能read_text(package, resource)
:
- The
package
可以是字符串或模块。
- The
resource
不再是路径,而只是现有包中要打开的资源的文件名;它可能不包含路径分隔符,并且可能没有子资源(即它不能是目录)。
对于问题中提出的示例,我们现在必须:
- 使
<your_package>/templates/
通过创建一个空的包到一个正确的包中__init__.py
文件在里面,
- 所以现在我们可以使用一个简单的(可能是相对的)
import
语句(不再解析包/模块名称),
- 并简单地要求
resource_name = "temp_file"
(没有路径)。
Tips:
- 访问文件在当前模块内,将包参数设置为
__package__
, e.g. impresources.read_text(__package__, 'temp_file')
(感谢@ben-mares)。
- 当事情变得有趣时实际文件名被问及
path()
,因为现在上下文管理器用于临时创建的文件(阅读this).
- 添加向后移植的库,有条件地适用于较旧的 Python,使用
install_requires=[" importlib_resources ; python_version<'3.7'"]
(check this如果你打包你的项目setuptools<36.2.1
).
- 记得删除
setuptools
图书馆从你的运行时要求,如果您从传统方法迁移。
- 记得定制
setup.py
or MANIFEST
to 包含任何静态文件.
- 您还可以设置
zip_safe=True
在你的setup.py
.