首页 > 解决方案 > 使用 dicts 的 dict 创建命名空间

问题描述

目前我正在使用json将字典保存到配置文件中。我加载它以将其转换为 adict然后将其转换为 aSimpleNamespace因为我更喜欢点符号来访问设置。为此,我加载它,如下例所示:

import json
from types import SimpleNamespace
SETTINGS = json.load(open("config.json", 'r'))
SETTINGS = SimpleNamespace(**SETTINGS)

但是,由于我当前正在将其加载dict到 aSimpleNamespace中,因此它不会在配置文件中加载子字典。例如,如果我这样做:

SETTINGS.server_info.port

我得到错误:

AttributeError: 'dict' object has no attribute 'port'

我想知道如何将所有字典作为名称空间加载到名称空间中,以便能够在字典中一直使用点表示法。

标签: pythonpython-3.xdictionary

解决方案


没有必要对返回的数据递归地应用转换json.load。您可以通过提供调用方法来简单地要求json.load返回实例而不是字典。这个方法“将在每个 JSON 对象的解码结果被调用,并且它的返回值将被用来代替给定的.” (来自文档)。SimpleNamespaceobject_hookjson.loaddict

最简单的object_hook可能如下所示:

def dict_to_sns(d):
    return SimpleNamespace(**d)

例如,给定以下输入:

{
  "settings": {
    "foo": {
      "number": 4,
      "size": "large"
    },
    "bar": {
      "color": "orange",
      "widgets": [
        "gizmo",
        "gadget",
        "thing"
      ]
    }
  }
}

我们可以做到以下几点:

>>> import json
>>> from types import SimpleNamespace
>>> def dict_to_sns(d):
...     return SimpleNamespace(**d)
... 
>>> with open('settings.json') as fd:
...     data = json.load(fd, object_hook=dict_to_sns)
... 
>>> data
namespace(settings=namespace(bar=namespace(color='orange', widgets=['gizmo', 'gadget', 'thing']), foo=namespace(number=4, size='large')))
>>> data.settings.foo
namespace(number=4, size='large')
>>> data.settings.foo.number
4
>>> data.settings.bar.widgets
['gizmo', 'gadget', 'thing']

推荐阅读