【问题标题】:Creating a namespace with a dict of dicts使用 dicts 的 dict 创建命名空间
【发布时间】:2018-11-02 14:09:33
【问题描述】:

目前我正在使用json 将字典保存到配置文件中。我加载它以将其转换为dict,然后将其转换为SimpleNamespace,因为我更喜欢点符号来访问设置。为此,我像下面的例子一样加载它:

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

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

SETTINGS.server_info.port

我得到错误:

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

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

【问题讨论】:

    标签: python python-3.x dictionary


    【解决方案1】:

    您必须递归地将SimpleNamespace 类应用于嵌套字典;对于这种情况,我更喜欢使用@functools.singledispatch()

    from functools import singledispatch
    from types import SimpleNamespace
    
    @singledispatch
    def wrap_namespace(ob):
        return ob
    
    @wrap_namespace.register(dict)
    def _wrap_dict(ob):
        return SimpleNamespace(**{k: wrap_namespace(v) for k, v in ob.items()})
    
    @wrap_namespace.register(list)
    def _wrap_list(ob):
        return [wrap_namespace(v) for v in ob]
    

    然后将其用作:

    with open('config.json') as settings_file:
        SETTINGS = wrap_namespace(json.load(settings_file))
    

    演示:

    >>> SETTINGS = wrap_namespace({'foo': 'bar', 'ham': {'spam': 'eggs', 'monty': [{'name': 'Eric Idle'}]}})
    >>> SETTINGS.foo
    'bar'
    >>> SETTINGS.ham.monty[0].name
    'Eric Idle'
    

    【讨论】:

      【解决方案2】:

      不必对json.load 返回的数据递归地应用转换。您可以通过向json.load 调用提供object_hook 方法来简单地要求json.load 返回SimpleNamespace 实例而不是字典。此方法“将在每个 JSON 对象解码的结果中调用,其返回值将用于代替给定的 dict。” (来自docs)。

      最简单的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']
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-26
        • 2023-03-14
        • 1970-01-01
        相关资源
        最近更新 更多