假设我有一个钥匙清单
key_lst = ["key1", "key2", "key3"]
我有一个价值
value = "my_value"
以及具有这种结构的示例dict my_dict
{
"key1": {
"key2": {
"key3": "some_value"
}
},
}
如何通过遍历/遍历value
来动态地将变量my_dict["key1"]["key2"]["key3"]
中的新值分配给key_lst
?
我不能只说my_dict["key1"]["key2"]["key3"] = value
,因为键和键的数量正在变化。我总是在列表中获取键(我必须在其中保存值的路径)...
我正在使用Python 3.7
答案 0 :(得分:6)
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'}}}
注释operator.getitem
用于访问dict.__getitem__
或其更常用的语法糖dict[]
。在这种情况下,functools.reduce
在getitem
上递归调用dataDict
,并依次使用mapList[:-1]
中的每个值作为参数。对于[:-1]
,我们有意遗漏了最后一个值,因此我们可以通过__setitem__
使用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'})})})})
答案 1 :(得分: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'}}}
d
是对字典的引用,而d2
是即弃引用,可在每次迭代时访问内部级别。
答案 2 :(得分:0)
我想您可以像这样遍历您的按键:
d = {}
a = d
for i in key_lst:
a[i] = {}
if i == key_lst[-1]:
a[i] = value
else:
a = a[i]
print(d)
# {'key1': {'key2': {'key3': 'my_value'}}}
编辑:我想我误解了问题,好像字典还不存在一样回答。 jpp answer非常简洁,否则我猜!
答案 3 :(得分:0)
这就是您想要的:
def update(d, key_lst , val):
for k in key_lst[:-1]:
if k not in d:
d[k] = {}
d = d[k]
d[key_lst[-1]] = val
d = {}
update(d, list('qwer'), 0)
# d = {'q': {'w': {'e': {'r': 0}}}}
您也可以使用defaultdict
,从某种意义上讲它很整洁,但是打印起来却很丑陋……:
from collections import defaultdict
nest = lambda: defaultdict(nest)
d = nest()
def update(d, key_lst , val):
for k in key_lst[:-1]:
d = d[k]
d[key_lst[-1]] = val
update(d, 'qwer', 0)
答案 4 :(得分:0)
key_lst = ["key1", "key2", "key3"]
my_dict={
"key1": {
"key2": {
"key3": "some_value"
}
},
}
val=my_dict
#loop gets second to last key in chain(path) and assigns it to val
for x in key_lst[:-1]:
val=val[x]
#now we can update value of last key, cause dictionary key is passed by reference
val[key_lst[-1]]="new value"
print (my_dict)
#{'key1': {'key2': {'key3': 'new value'}}}