Python:更新深层嵌套字典中的值

时间:2016-12-15 06:17:22

标签: python dictionary

我正在导入和操作一些深层嵌套的JSON(作为字典导入)。它可以使用以下代码分配值:

query['query']['function_score']['query']['multi_match']['operator'] = 'or'
query['query']['function_score']['query']['multi_match'].update({
        'minimum_should_match' : '80%' })  
但是它像坚果一样丑陋而笨重。我想知道是否有一种更清晰的方法可以为深度嵌套的密钥分配值,并且效率相当高?

我已经读过有关可能使用内存中的SQLlite数据库的信息,但是经过一些操作后数据又回到了json中。

3 个答案:

答案 0 :(得分:3)

multi_match = query['query']['function_score']['query']['multi_match']
multi_match['operator'] = 'or'
multi_match.update({'minimum_should_match' : '80%' })

答案 1 :(得分:2)

JSONPath(通过' jsonpath_rw')使它不那么麻烦:

一个:

>>> query
{u'query': {u'function_score': {u'query': {u'multi_match': {u'min_should_match': u'20%'}}}}}

更新

>>> found = jsonpath_rw.parse("$..multi_match").find(query)[0]
>>> found.value["operator"] == "or"
>>> found.value["min_should_match"] = "80%"`

然后:

>>> query
{u'query': {u'function_score': {u'query': {u'multi_match': {'min_should_match': '80%', u'operator': u'or'}}}}}

答案 2 :(得分:0)

选择的答案肯定是要走的路。我(稍后)发现的问题是我的嵌套密钥可以出现在不同的级别。所以我需要能够遍历dict并首先找到节点的路径,然后进行更新或添加。

jsonpath_rw是最直接的解决方案,但我尝试使用它时得到了一些奇怪的结果。经过几个小时的摔跤,我放弃了。

冒着成为一个笨重的新手而被击落的风险,我最终充实了一些功能(基于我在SO上找到的其他代码),这些功能原生地做了一些很好的事情来满足我的需求:

def find_in_obj(obj, condition, path=None):
    ''' generator finds full path to nested dict key when key is at an unknown level 
        borrowed from http://stackoverflow.com/a/31625583/5456148'''
    if path is None:
        path = []

    # In case this is a list
    if isinstance(obj, list):
        for index, value in enumerate(obj):
            new_path = list(path)
            new_path.append(index)
            for result in find_in_obj(value, condition, path=new_path):
                yield result

    # In case this is a dictionary
    if isinstance(obj, dict):
        for key, value in obj.items():
            new_path = list(path)
            new_path.append(key)
            for result in find_in_obj(value, condition, path=new_path):
                yield result

            if condition == key:
                new_path = list(path)
                new_path.append(key)
                yield new_path


def set_nested_value(nested_dict, path_list, key, value):
    ''' add or update a value in a nested dict using passed list as path
        borrowed from http://stackoverflow.com/a/11918901/5456148'''
    cur = nested_dict
    path_list.append(key)
    for path_item in path_list[:-1]:
        try:
            cur = cur[path_item]
        except KeyError:
            cur = cur[path_item] = {}

    cur[path_list[-1]] = value
    return nested_dict


def update_nested_dict(nested_dict, findkey, updatekey, updateval):
    ''' finds and updates values in nested dicts with find_in_dict(), set_nested_value()'''
    return set_nested_value(
        nested_dict,
        list(find_in_obj(nested_dict, findkey))[0],
        updatekey,
        updateval
    )

find_in_obj()是一个生成器,用于查找指定嵌套键的路径。

set_nested_values()将在给定列表的dict中更新键/值,或者如果它不存在则添加

update_nested_dict()是"包装器"对于嵌套字典中要搜索的两个函数,您要查找的密钥以及要更新的密钥值(如果它不存在则添加)。

所以我可以传入:

q = update_nested_dict(q, 'multi_match', 'operator', 'or')
q = update_nested_dict(q, 'multi_match', 'minimum_should_match', '80%')

"运营商"值已更新,并且" minimum_should_match'键/值添加在' multi_match'节点,无论它出现在字典中的哪个级别。

如果搜索到的密钥存在于字典中的多个位置,则可能会遇到问题。