你可以使用reduce
:
In [17]: doc = { 'A':1, 'B':1, 'C':{'C-A':2, 'C-B':{'C-B-A':3}}}
...:
...: def get(doc, *args):
...: return reduce(dict.get, args, doc)
In [18]: get(doc, 'A')
Out[18]: 1
In [19]: get(doc, 'C', 'C-A')
Out[19]: 2
In [20]: get(doc, 'C', 'C-B', 'C-B-A')
Out[20]: 3
你可以这样想reduce
:
def reduce(function, arguments, initializer):
a = initializer
for b in arguments:
a = function(a, b)
return a
即它在给定的参数上“累积”调用二进制函数的值。在您的情况下,首先a
是doc
. 然后,它变成 的结果doc[arguments[0]]
。如果arguments
长度为一,则迭代停止并返回结果,否则它是子字典之一,并且在下一次迭代中,循环将从该子字典中获取一个值。
请注意,使用递归意味着将深度限制为sys.getrecursionlimit()
,通常约为 1000,并且它会慢得多,因为您至少要执行两次函数调用来检索值:
In [84]: def get(doc, *args):
...: return reduce(dict.get, args, doc)
In [85]: def get2(doc, *args):
...: return get2(doc[args[0]], *args[1:]) if args else doc
In [86]: %timeit get(doc, 'C', 'C-B', 'C-B-A')
1000000 loops, best of 3: 621 ns per loop
In [87]: %timeit get2(doc, 'C', 'C-B', 'C-B-A')
1000000 loops, best of 3: 1.04 us per loop
In [88]: d = make_dict(depth=350)
In [89]: %timeit get(d, *range(350))
10000 loops, best of 3: 38.9 us per loop
In [90]: %timeit get2(d, *range(350))
1000 loops, best of 3: 973 us per loop
这使用了一个浅字典。如果您尝试使用深度更大的 dict,则与功能解决方案相比,递归解决方案将变得越来越慢。