gpt4 book ai didi

python - 如何从 Python 包中读取(静态)文件?

转载 作者:IT老高 更新时间:2023-10-28 21:44:35 26 4
gpt4 key购买 nike

您能告诉我如何读取 Python 包中的文件吗?

我的情况

我加载的包有许多我想从程序中加载的模板(用作字符串的文本文件)。但是如何指定此类文件的路径?

假设我想从以下位置读取文件:

package\templates\temp_file

某种路径操作?包基本路径跟踪?

最佳答案

TLDR; 使用标准库的 importlib.resources module如下面方法 2 中所述。

传统 pkg_resources from setuptools 不再推荐,因为新方法:

  • 它是 significantly more performant ;
  • 更安全,因为使用包(而不是路径字符串)会引发编译时错误;
  • 它更直观,因为您不必“加入”路径;
  • 开发时速度更快,因为您不需要额外的依赖项 (setuptools),而只依赖 Python 的标准库。

我把传统的先列出来,以说明移植现有代码时与新方法的区别(也移植explained here)。



假设您的模板位于嵌套在模块包内的文件夹中:

  <your-package>
+--<module-asking-the-file>
+--templates/
+--temp_file <-- We want this file.

Note 1: For sure, we should NOT fiddle with the __file__ attribute (e.g. code will break when served from a zip).

Note 2: If you are building this package, remember to declatre your data files as package_data or data_files in your setup.py.

1) 使用 pkg_resources来自 setuptools (慢)

您可以使用 pkg_resources 来自 setuptools 发行版的软件包,但 需要付费,performance-wise :

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:

  • This will read data even if your distribution is zipped, so you may set zip_safe=True in your setup.py, and/or use the long-awaited zipapp packer from python-3.5 to create self-contained distributions.

  • Remember to add setuptools into your run-time requirements (e.g. in install_requires`).

...请注意,根据 Setuptools/pkg_resources docs,您不应该使用 os.path.join :

Basic Resource Access

Note that resource names must be /-separated paths and cannot be absolute (i.e. no leading /) or contain relative names like "..". Do not use os.path routines to manipulate resource paths, as they are not filesystem paths.

2) Python >= 3.7,或使用向后移植的 importlib_resources 图书馆

使用标准库的 importlib.resources modulesetuptools 更有效, 上:

try:
import importlib.resources as pkg_resources
except ImportError:
# Try backported to PY<37 `importlib_resources`.
import importlib_resources as pkg_resources

from . import templates # relative-import the *package* containing the templates

template = pkg_resources.read_text(templates, 'temp_file')
# or for a file-like stream:
template = pkg_resources.open_text(templates, 'temp_file')

Attention:

Regarding the function read_text(package, resource):

  • The package can be either a string or a module.
  • The resource is NOT a path anymore, but just the filename of the resource to open, within an existing package; it may not contain path separators and it may not have sub-resources (i.e. it cannot be a directory).

对于问题中提出的示例,我们现在必须:

  • 制作<your_package>/templates/通过创建一个空的 __init__.py 到一个适当的包中文件,
  • 所以现在我们可以使用一个简单的(可能是相对的)import声明(不再解析包/模块名称),
  • 只需询问 resource_name = "temp_file" (没有路径)。

Tips:

  • To access a file inside the current module, set the package argument to __package__, e.g. pkg_resources.read_text(__package__, 'temp_file') (thanks to @ben-mares).
  • Things become interesting when an actual filename is asked with path(), since now context-managers are used for temporarily-created files (read this).
  • Add the backported library, conditionally for older Pythons, with install_requires=[" importlib_resources ; python_version<'3.7'"] (check this if you package your project with setuptools<36.2.1).
  • Remember to remove setuptools library from your runtime-requirements, if you migrated from the traditional method.
  • Remember to customize setup.py or MANIFEST to include any static files.
  • You may also set zip_safe=True in your setup.py.

关于python - 如何从 Python 包中读取(静态)文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6028000/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com