如果键在列表中,如何更新嵌套字典中的值?

Dav*_*yer 4 python dictionary nested python-3.x

假设我有一个键列表

key_lst = ["key1", "key2", "key3"]
Run Code Online (Sandbox Code Playgroud)

我有一个价值

value = "my_value"
Run Code Online (Sandbox Code Playgroud)

以及my_dict具有此结构的示例dict

{
"key1": {
    "key2": {
        "key3": "some_value"
        }
    },
}
Run Code Online (Sandbox Code Playgroud)

如何通过遍历/循环value来动态地将变量中的新值分配给?my_dict["key1"]["key2"]["key3"]key_lst

我不能只说my_dict["key1"]["key2"]["key3"] = value因为钥匙和钥匙的数量正在改变.我总是在列表中获取密钥(我必须保存值的路径)...

我正在使用Python 3.7

jpp*_*jpp 7

预定义的字典结构: functools.reduce

您可以使用重复functools.reduce应用定义函数getitem,然后设置提供的值:

from functools import reduce
from operator import getitem

def set_nested_item(dataDict, mapList, val):
    """Set item in nested dictionary"""
    reduce(getitem, mapList[:-1], dataDict)[mapList[-1]] = val
    return dataDict

key_lst = ["key1", "key2", "key3"]
value = "my_value"
d = {"key1": {"key2": {"key3": "some_value"}}}

d = set_nested_item(d, key_lst, value)

print(d)
# {'key1': {'key2': {'key3': 'my_value'}}}
Run Code Online (Sandbox Code Playgroud)

注意operator.getitem用于访问dict.__getitem__,或其更常用的语法糖dict[].在这种情况下,functools.reduce调用getitem递归上dataDict,先后使用中的每个值mapList[:-1]作为参数.有了[:-1],我们故意省去最后一个值,所以我们可以使用__setitem__via dict[key] = value作为最后一个键.


任意字典嵌套: collections.defaultdict

如果您希望在尚未定义的任意分支中添加项目,您可以构建一个defaultdict.为此,您可以先defaultify输入常规字典,然后set_nested_item像以前一样使用:

from collections import defaultdict

def dd_rec():
    return defaultdict(dd_rec)

def defaultify(d):
    if not isinstance(d, dict):
        return d
    return defaultdict(dd_rec, {k: defaultify(v) for k, v in d.items()})

dd = defaultify(d)

key_lst = ["key1", "key2", "key5", "key6"]
value = "my_value2"
dd = set_nested_item(dd, key_lst, value)

print(dd)

# defaultdict(<function __main__.<lambda>>,
#             {'key1': defaultdict(<function __main__.<lambda>>,
#                          {'key2': defaultdict(<function __main__.<lambda>>,
#                                       {'key3': 'my_value',
#                                        'key5': defaultdict(<function __main__.<lambda>>,
#                                                    {'key6': 'my_value2'})})})})
Run Code Online (Sandbox Code Playgroud)

  • 但这假设特定结构已经存在.设置新值怎么样?你需要一个defaultdict,对吧?这不能处理KeyErrors. (2认同)

cs9*_*s95 5

您可以setdefault在循环中迭代地构建/访问级别:

d = {}
d2 = d
for k in key_lst[:-1]:
    d2 = d2.setdefault(k, {})

d2[key_lst[-1]] = value
print(d)
# {'key1': {'key2': {'key3': 'my_value'}}}
Run Code Online (Sandbox Code Playgroud)

d是对您的字典的引用,并且d2是在每次迭代时访问内部级别的一次性引用.