Pythonic访问递归嵌套dict的方法

wim*_*wim 5 python recursion dictionary

在一般情况下,我们如何对嵌套dicts进行递归访问?

from collections import defaultdict

D = lambda: defaultdict(D)
d = D()

keys = ['k1', 'k2', 'k3']
value = 'v'

if len(keys) == 3:
    k1, k2, k3 = keys
    d[k1][k2][k3] = value
else:
    ???
Run Code Online (Sandbox Code Playgroud)

我走下去的一些可怕的路径reduce,d.__getitem__d.__setitem__但觉得有肯定是一个更优雅的方式...

dan*_*ano 5

这很丑陋,但这有效:

def set_val(d, keys, val):
    reduce(lambda x,y: x[y], keys[:-1], d)[keys[-1]] = val
Run Code Online (Sandbox Code Playgroud)

稍微更易读的版本:

def set_val(d, keys, val):
    last = keys[-1]  # Key we want to set val on
    search_keys = keys[:-1]  # Keys we need to traverse
    reduce(lambda x,y: x[y], search_keys, d)[last] = val
Run Code Online (Sandbox Code Playgroud)

用法:

>>> from collections import defaultdict
>>> D = lambda: defaultdict(D)
>>> d = D()
>>> set_val(d, ['k1', 'k2', 'k3'], "hi")
>>> d
defaultdict(<function <lambda> at 0x7fbd365ac7d0>, {'k1': defaultdict(<function <lambda> at 0x7fbd365ac7d0>, {'k2': defaultdict(<function <lambda> at 0x7fbd365ac7d0>, {'k3': 'hi'})})})
>>> d['k1']['k2']['k3']
'hi'
Run Code Online (Sandbox Code Playgroud)

它用于reduce到达请求的最里面的 dict ( keys[:-1]),然后将列表中的最后一个键设置为所需的值 ( output_of_reduce[keys[-1]] = val)。

请注意,在 Python 3 中,您需要一个 fromfunctools import reduce才能使用它。

为了清楚起见,以下是扩展的代码:

def set_val(d, keys, val):
    out = d
    for k in keys[:-1]:
        out = out[k]
    out[keys[-1]] = val
Run Code Online (Sandbox Code Playgroud)