您将如何基于列表的值来修改/创建嵌套dict的dict中的键/值,其中列表的最后一项是dict的值,而其余项会返回到dict中的键?这将是列表:
list_adddress = [ "key1", "key1.2", "key1.2.1", "value" ]
仅在诸如解析命令行参数之类的情况下,这才是问题。显然,在脚本中修改/创建此值将非常容易dict_nested["key1"]["key1.2"]["key1.2.1"]["value"]。
dict_nested["key1"]["key1.2"]["key1.2.1"]["value"]
这将是字典的嵌套字典:
dict_nested = { "key1": { "key1.1": { "...": "...", }, "key1.2": { "key1.2.1": "change_this", }, }, "key2": { "...": "..." }, }
我猜在这种情况下,将需要诸如递归函数或列表理解之类的东西。
def ValueModify(list_address, dict_nested): ... ... ValueModify(..., ...)
另外,如果中的项目list_address会重新引用不存在的字典中的键,则应创建它们。
list_address
单线:
keys, (newkey, newvalue) = list_address[:-2], list_address[-2:] reduce(dict.__getitem__, keys, dict_nested)[newkey] = newvalue
注:dict.get与operator.getitem将在这里产生错误的异常。
dict.get
operator.getitem
乔尔·科内特(Joel Cornett)的答案中明确的for循环可能更具可读性。
如果要创建不存在的中间词典:
reduce(lambda d,k: d.setdefault(k, {}), keys, dict_nested)[newkey] = newvalue
如果要覆盖不是字典的现有中间值,例如字符串,整数:
from collections import MutableMapping def set_value(d, keys, newkey, newvalue, default_factory=dict): """ Equivalent to `reduce(dict.get, keys, d)[newkey] = newvalue` if all `keys` exists and corresponding values are of correct type """ for key in keys: try: val = d[key] except KeyError: val = d[key] = default_factory() else: if not isinstance(val, MutableMapping): val = d[key] = default_factory() d = val d[newkey] = newvalue
list_address = ["key1", "key1.2", "key1.2.1", "key1.2.1.1", "value"] dict_nested = { "key1": { "key1.1": { "...": "...", }, "key1.2": { "key1.2.1": "change_this", }, }, "key2": { "...": "..." }, } set_value(dict_nested, list_address[:-2], *list_address[-2:]) assert reduce(dict.get, list_address[:-1], dict_nested) == list_address[-1]
>>> from collections import OrderedDict >>> d = OrderedDict() >>> set_value(d, [], 'a', 1, OrderedDict) # non-existent key >>> d.items() [('a', 1)] >>> set_value(d, 'b', 'a', 2) # non-existent intermediate key >>> d.items() [('a', 1), ('b', {'a': 2})] >>> set_value(d, 'a', 'b', 3) # wrong intermediate type >>> d.items() [('a', {'b': 3}), ('b', {'a': 2})] >>> d = {} >>> set_value(d, 'abc', 'd', 4) >>> reduce(dict.get, 'abcd', d) == d['a']['b']['c']['d'] == 4 True >>> from collections import defaultdict >>> autovivify = lambda: defaultdict(autovivify) >>> d = autovivify() >>> set_value(d, 'abc', 'd', 4) >>> reduce(dict.get, 'abcd', d) == d['a']['b']['c']['d'] == 4 True >>> set_value(1, 'abc', 'd', 4) #doctest:+IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... TypeError: >>> set_value([], 'abc', 'd', 4) #doctest:+IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... TypeError: >>> L = [10] >>> set_value(L, [0], 2, 3) >>> L [{2: 3}]