Ram*_*hum 44 python resources distutils setuptools decoupling
我有一个Python项目,其中我使用了许多非代码文件.目前这些都是图像,但我将来可能会使用其他类型的文件.什么是存储和引用这些文件的好方案?
我考虑在主目录中创建一个文件夹"resources",但是有一个问题; 有些图像是从我项目的子包中使用的.以这种方式存储这些图像会导致耦合,这是一个缺点.
另外,我需要一种方法来访问这些文件,这些文件与我当前的目录无关.
Pav*_*pin 52
您可能想要使用pkg_resources附带的库setuptools.
例如,我编写了一个快速的小包"proj"来说明我使用的资源组织方案:
proj/setup.py proj/proj/__init__.py proj/proj/code.py proj/proj/resources/__init__.py proj/proj/resources/images/__init__.py proj/proj/resources/images/pic1.png proj/proj/resources/images/pic2.png
请注意我如何将所有资源保存在单独的子包中.
"code.py"显示如何pkg_resources用于引用资源对象:
from pkg_resources import resource_string, resource_listdir
# Itemize data files under proj/resources/images:
print resource_listdir('proj.resources.images', '')
# Get the data file bytes:
print resource_string('proj.resources.images', 'pic2.png').encode('base64')
Run Code Online (Sandbox Code Playgroud)
如果你运行它,你会得到:
['__init__.py', '__init__.pyc', 'pic1.png', 'pic2.png'] iVBORw0KGgoAAAANSUhE ...
如果需要将资源视为文件对象,请使用resource_stream().
访问资源的代码可能位于项目的子包结构中的任何位置,它只需要通过全名引用包含图像的子包:proj.resources.images在本例中.
这是"setup.py":
#!/usr/bin/env python
from setuptools import setup, find_packages
setup(name='proj',
packages=find_packages(),
package_data={'': ['*.png']})
Run Code Online (Sandbox Code Playgroud)
警告:
为了"本地"测试,即没有先安装软件包,你必须从具有的目录调用测试脚本setup.py.如果你在同一个目录中code.py,Python就不会知道proj包.所以这样的事情proj.resources无法解决.
在每个需要它的子包中,您始终可以有一个单独的“ resources”文件夹,并使用os.path函数从__file__子包的值中获取这些文件夹。为了说明我的意思,我__init__.py在三个位置创建了以下文件:
c:\ temp \ topp(顶级程序包) c:\ temp \ topp \ sub1(子包1) c:\ temp \ topp \ sub2(子包2)
这是__init__.py文件:
import os.path
resource_path = os.path.join(os.path.split(__file__)[0], "resources")
print resource_path
Run Code Online (Sandbox Code Playgroud)
在c:\ temp \ work中,我创建一个应用程序topapp.py,如下所示:
import topp
import topp.sub1
import topp.sub2
Run Code Online (Sandbox Code Playgroud)
这表示使用topp包和子包的应用程序。然后我运行它:
C:\ temp \ work> topapp
追溯(最近一次通话):
文件“ C:\ temp \ work \ topapp.py”,第1行,在
进口topp
ImportError:没有名为topp的模块
符合预期。我们将PYTHONPATH设置为模拟将程序包放在路径上:
C:\ temp \ work>设置PYTHONPATH = c:\ temp C:\ temp \ work> topapp c:\ temp \ topp \ resources c:\ temp \ topp \ sub1 \ resources c:\ temp \ topp \ sub2 \ resources
如您所见,资源路径正确解析为路径上实际(子)程序包的位置。
更新: 这是相关的py2exe文档。
这样做的新方法是使用importlib. 对于 3.7 之前的 Python 版本,您可以添加依赖项importlib_resources并执行类似的操作
from importlib_resources import files
def get_resource(module: str, name: str) -> str:
"""Load a textual resource file."""
return files(module).joinpath(name).read_text(encoding="utf-8")
Run Code Online (Sandbox Code Playgroud)
如果您的资源位于foo/resources子模块中,那么您将get_resource像这样使用
resource_text = get_resource('foo.resources', 'myresource')
Run Code Online (Sandbox Code Playgroud)