尝试在 Python 包中读取 JSON 文件

Posted

技术标签:

【中文标题】尝试在 Python 包中读取 JSON 文件【英文标题】:Trying to read JSON file within a Python package 【发布时间】:2020-06-26 11:30:51 【问题描述】:

我正在打包一个 python 包,我将其称为MyPackage

包结构为:

MyPackage/
    script.py
    data.json

data.json 文件包含在script.py 中读取的缓存数据。

我已经弄清楚如何包含数据文件(使用 setuptools include_package_data=True 并在 MANIFEST.in 文件中包含数据文件的路径)但是现在当我 pip 安装此包并导入已安装的 MyPackage 时(目前正在测试通过pip 从 GitHub 存储库安装)我在要使用 MyPackage 的脚本中收到 FileNotFound 异常(data.json)。但是,我看到data.json文件确实安装在Lib/site-packages/MyPackage中。

我在这里尝试读取包中的 json 文件是不是做错了什么?

请注意,在script.py 中,我试图将data.json 读取为open('data.json', 'r')

我是不是搞砸了有关数据文件路径的问题?

【问题讨论】:

欢迎来到 Stack Overflow。你能分享你的代码吗?如果你愿意,帮助你会更容易。 请提供完整的错误信息以及minimal reproducible example。 如果答案解决了您的问题,您应该在答案左侧accept it by clicking the green check mark。完整的解释见this meta thread。 【参考方案1】:

您并没有搞砸什么,访问包资源只是有点棘手 - 主要是因为它们可以打包成您的 .json 可能严格来说不作为安装包的系统上的实际文件存在的格式(例如zip-app)。访问数据文件的正确方法不是通过指定路径(如"MyPackage/data.json"),而是通过将其作为已安装包的资源进行访问(如"MyPackage.data.json")。这种区别可能看起来很迂腐,但它可能很重要。

无论如何,访问应该使用内置的importlib.resources模块:

import importlib.resources
import json

with importlib.resources.open_text("MyPackage", "data.json") as file:
    data = json.load(file)  
# you should be able to access 'data' like a dictionary here

如果您碰巧使用低于 3.7 的 python 版本,则必须从 pyPI 将其安装为 importlib_resources

【讨论】:

啊太棒了!我发布答案后才看到这个。我会试试这个,谢谢!有趣的是,我认为离散化现有脚本的一部分相对容易,但我在将近 2 小时后...哈 是的,打包代码很快就会变成一团糟=) 我想知道 Python 3.9 中是否发生了一些变化? AttributeError: 'WindowsPath' object has no attribute 'read' 对我而言,您的示例代码的精确副本崩溃了文档建议“上下文管理器提供了一个 pathlib.Path 对象”,因此我假设它按预期工作,但这会使您的示例无效。我错过了什么吗? @MantasKandratavicius 嗯.. 不,你是对的。看来我上传了错误的代码,但仍然设法获得了一堆赞成票。 json.load 需要一个文件句柄,而不是路径对象,所以你需要先在那里调用open()。现在已经修复了,谢谢指出。 您也可以使用importlib.resources.open_text,如with importlib.resources.open_text("MyPackage", "data.json") as data_file: data = json.load(data_file),而不是使用double with's【参考方案2】:

我通过获取包所在位置的“相对路径”解决了这个问题。

self.data = self.load_data(path=os.path.join(
                os.path.dirname(os.path.abspath(__file__)),
                'data.json'))

load_data只是读取数据文件

仍然非常欢迎任何建设性的批评。如果我帮不上忙,就不要尝试编写愚蠢的代码:)

【讨论】:

如果这是一个您可以完全控制的简单包,那么这样做可能就足够了。一种可能失败的情况是,如果您将软件包安装为压缩存档。

以上是关于尝试在 Python 包中读取 JSON 文件的主要内容,如果未能解决你的问题,请参考以下文章

ValueError:尝试在非包中进行相对导入[重复]

自定义python包中的对象范围

读取并更新到主应用程序包中的 JSON 文件

Python包中 __init__.py文件的作用

在 Python 包中查找数据文件 - setup.py 的 package_data=... 可能已损坏?

Python模块包中__init__.py文件的作用