56

我有一个 Python 项目,其中使用了许多非代码文件。目前这些都是图像,但我将来可能会使用其他类型的文件。什么是存储和引用这些文件的好方案?

我考虑只是在主目录中创建一个文件夹“资源”,但是有一个问题;我的项目的子包中使用了一些图像。以这种方式存储这些图像会导致耦合,这是一个缺点。

此外,我需要一种访问这些文件的方法,该方法与我当前的目录无关。

4

4 回答 4

63

您可能想pkg_resources使用setuptools.

例如,我制作了一个快速的小包"proj"来说明我将使用的资源组织方案:

项目/setup.py
项目/项目/__init__.py
项目/项目/code.py
项目/项目/资源/__init__.py
项目/项目/资源/图像/__init__.py
项目/项目/资源/图像/pic1.png
项目/项目/资源/图像/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')

如果你运行它,你会得到:

['__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']})

警告: 要在“本地”测试事物,即先不安装软件包,您必须从具有setup.py. 如果您与 位于同一目录中code.py,Python 将不知道proj包。所以像这样的事情proj.resources不会解决。

于 2009-09-08T22:22:05.287 回答
6

您始终可以在每个需要它的子包中拥有一个单独的“资源”文件夹,并使用函数从子包的值中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

在 c:\temp\work 中,我创建了一个 app,topapp.py,如下:

import topp
import topp.sub1
import topp.sub2

这表示使用topp包和子包的应用程序。然后我运行它:

C:\temp\work>topapp
回溯(最近一次通话最后):
  文件“C:\temp\work\topapp.py”,第 1 行,在
    进口顶级
ImportError:没有名为 topp 的模块

正如预期的那样。我们设置 PYTHONPATH 来模拟我们的包在路径上:

C:\temp\work>设置 PYTHONPATH=c:\temp

C:\temp\work>topapp
c:\temp\topp\资源
c:\temp\topp\sub1\resources
c:\temp\topp\sub2\resources

如您所见,资源路径正确解析为路径上实际(子)包的位置。

更新: 是相关的 py2exe 文档。

于 2009-09-08T18:50:26.183 回答
6

这样做的新方法是使用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")

如果您的资源位于foo/resources子模块中,那么您将get_resource像这样使用

resource_text = get_resource('foo.resources', 'myresource')
于 2020-10-23T16:03:30.220 回答
1

@ pycon2009,有一个关于 distutils 和 setuptools 的演讲。你可以在这里找到所有的视频

Python 中的 Eggs 和 Buildout 部署 - 第 1 部分

Python 中的 Eggs 和 Buildout 部署 - 第 2 部分

Python 中的 Eggs 和 Buildout 部署 - 第 3 部分

在这些视频中,它们描述了如何在包中包含静态资源。我相信它在第 2 部分。

使用 setuptools,您可以定义依赖关系,这将允许您拥有 2 个使用来自第 3 个包的资源的包。

Setuptools 还为您提供了访问这些资源的标准方法,并允许您在包中使用相对路径,从而无需担心包的安装位置。

于 2009-09-24T16:16:28.443 回答