【问题标题】:Python 3 use kwargs to replace nested dictionary valuesPython 3 使用 kwargs 替换嵌套字典值
【发布时间】:2018-04-19 04:48:02
【问题描述】:

我已经搜索了文档并在许多队友的帮助下使用,但无法弄清楚如何通过(在我的情况下)测试函数将字典替换为 kwargs 提供的值:

模板字典:

{
    "id": "id_1234",
    "integer_value": 1234,
    "level_one": {
        "id": 1234,
        "foo": "true",
        "list_one": [],
        "list_two": [
            522
        ],
        "url": "http://google.com",
        "level_two": {
            "thing_one": {
                "yes": "false",
                "no": "false"
            },
            "thing_two": {
                "yes": "false",
                "no": "false"
            }
        },
        "another_field": "true",
        "bar": 15000
    }
}

递归字典函数:

def update_dictionary(template_dict, **kwargs):
for k, v in kwargs.items():
    print(v)
    print(isinstance(v, collections.Mapping))
    if isinstance(v, collections.Mapping):
        print("This is the k value")
        print(k)
        template_dict[k] = update_dictionary(template_dict.get(k, {}), v)
    else:
        print("We're going into the else now")
        template_dict[k] = v
return template_dict

我从这里的另一个论坛获得了上述功能,但是在传递 kwargs 时它似乎不起作用。对于不在嵌套字典第一级中的任何字段,isinstance 检查结果为 False。任何帮助表示赞赏!

通过 kwargs 的测试行:

new_dict = update_dictionary(template_dict, another_field = 'false', integer_value=12345)

【问题讨论】:

  • 键永远不会是collections.Mapping 的实例,至少在您实现可散列映射之前不会。你的意思可能是isinstance(v, collections.Mapping)
  • 啊,是的,这是我的错字。 (v, collections.Mapping) 在这种情况下也为所有嵌套的字典键返回 False。
  • 另外,你需要继续传递**kwargs ....

标签: python python-3.x dictionary recursion


【解决方案1】:

所以,你需要继续传递kwargs,否则第一级之后的所有内容都没有任何东西可以替换!这是一个简单粗暴的演示:

def update_dict(d, **kwargs):
    new = {}
    for k, v in d.items():
        if isinstance(v, dict):
            new[k] = update_dict(v, **kwargs)
        else:
            new[k] = kwargs.get(k, v)
    return new

在行动:

In [16]: template
Out[16]:
{'id': 'id_1234',
 'integer_value': 1234,
 'level_one': {'another_field': 'true',
  'bar': 15000,
  'foo': 'true',
  'id': 1234,
  'level_two': {'thing_one': {'no': 'false', 'yes': 'false'},
   'thing_two': {'no': 'false', 'yes': 'false'}},
  'list_one': [],
  'list_two': [522],
  'url': 'http://google.com'}}

In [17]: update_dict(template, another_field = 'false', integer_value=12345)
Out[17]:
{'id': 'id_1234',
 'integer_value': 12345,
 'level_one': {'another_field': 'false',
  'bar': 15000,
  'foo': 'true',
  'id': 1234,
  'level_two': {'thing_one': {'no': 'false', 'yes': 'false'},
   'thing_two': {'no': 'false', 'yes': 'false'}},
  'list_one': [],
  'list_two': [522],
  'url': 'http://google.com'}}

再说一遍:

In [19]: update_dict(template, another_field = 'false', integer_value=12345, no='FOO')
Out[19]:
{'id': 'id_1234',
 'integer_value': 12345,
 'level_one': {'another_field': 'false',
  'bar': 15000,
  'foo': 'true',
  'id': 1234,
  'level_two': {'thing_one': {'no': 'FOO', 'yes': 'false'},
   'thing_two': {'no': 'FOO', 'yes': 'false'}},
  'list_one': [],
  'list_two': [522],
  'url': 'http://google.com'}}

注意,这个实现返回一个全新的dict,我认为这是你想要的,因为template是一个模板,你写道:

new_dict = update_dictionary(template_dict, another_field = 'false', integer_value=12345)

但如果您实际上想就地修改,您可以简单地更改为:

def update_dict(d, **kwargs):
    for k, v in d.items():
        if isinstance(v, dict):
            update_dict(v, **kwargs)
        else:
            d[k] = kwargs.get(k, v)

我会使用非就地版本...请注意,您可以使用厚颜无耻的单线来执行此操作,但我不推荐它:

def update_dict(d, **kwargs):
    return {k:update_dict(v, **kwargs) if isinstance(v, dict) else kwargs.get(k,v) for k,v in d.items()}

【讨论】:

  • 非常感谢!事实上,我确实需要就地修改,所以我使用了你的建议,并将 (v, dict) 替换为 (v, collections.Mapping),因为我还有一些其他数据类型也需要修改。我一直在检查 kwargs 而不是模板字典!现在一切都说得通了
猜你喜欢
  • 2019-09-06
  • 2019-01-25
  • 2023-01-23
  • 2022-10-13
  • 1970-01-01
  • 2016-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多