如何在Python包中包含资源并从代码中访问?
解决方法
一、先修正打包配置(setup.py)
你之前的配置不对,因为resources目录不在src/mypackage这个包的内部,package_data是用来指定包内资源的,得调整配置或者目录结构:
方案1:把资源移到包内(推荐)
先改目录结构,把resources挪到src/mypackage下面:
my-package - |- src/mypackage | |- resources/some-resources |- setup.py |- setup.cfg
然后修改setup.py:
from setuptools import setup setup( # 其他原有配置(比如name、version这些) packages=["mypackage"], package_dir={"": "src"}, # 指定包的根目录在src下 package_data={ "mypackage": ["resources/**/*"] # 匹配resources下所有文件和子目录 }, include_package_data=True, )
方案2:保留原目录结构,用data_files
如果不想动目录,就用data_files把外部资源打包:
from setuptools import setup setup( # 其他原有配置 packages=["mypackage"], package_dir={"": "src"}, data_files=[ # 第一个参数是安装后的目标目录,第二个是要打包的资源路径 ("mypackage_resources", ["resources/some-resources/*"]) ], )
这种方式资源会被装到site-packages下的单独目录,访问起来不如包内资源方便。
二、在代码里访问资源
别用pkg_resources了,Python 3.7+ 有内置的importlib.resources,更简单还没额外依赖:
如果用方案1(资源在包内)
在src/mypackage的任意代码文件里这么写:
from importlib.resources import files, as_file # 获取resources目录的对象 resource_dir = files("mypackage.resources") # 遍历目录里的文件 for item in resource_dir.iterdir(): print(item.name) # 读取某个资源文件的内容 with as_file(resource_dir / "你的资源文件名") as f: content = f.read_text() print(content)
如果用方案2(data_files安装)
得先找到资源的安装路径:
import os from importlib.metadata import distribution # 获取包的安装路径 dist = distribution("你的包名(setup里的name)") resource_path = os.path.join(dist.locate_file(""), "mypackage_resources") # 读取资源文件 with open(os.path.join(resource_path, "你的资源文件名"), "r") as f: content = f.read()
为啥之前的pkg_resources没用?
你用pkg_resources.resource_listdir("mypackage", "")只能看到Python文件,是因为resources根本不在mypackage的包范围内,pkg_resources只会扫包内的文件,所以要么把资源挪进包,要么用正确的配置把资源包含进来。
内容的提问来源于stack exchange,提问作者Conor
相关产品推荐
相关产品推荐

