Python安全的字典导航,正确的方式

psm*_*may 5 python dictionary idioms

TLDR摘要

我编写了navigateDict一个在a上进行安全导航的函数dict,类似于dict.get()嵌套.它取代了像

if 1 in data and 'i' in data[1] and 'a' in data[1]['i']:
    print data[1]['i']['a']
else:
    print "Not found"
Run Code Online (Sandbox Code Playgroud)

与大致相当

found = navigateDict(data, 1, 'i', 'a')
if found is not None:
    print found
else:
    print "Not found"
Run Code Online (Sandbox Code Playgroud)
  • 是否有类似于此标准库的一部分?
  • 是否有更惯用的方式来做同样的事情?
    • 任何需要多次输入任何路径组件键的响应可能都是非答案.

额外细节

实施如下:

# Allow fallback value other than None
def navigateDictEx(d, keys, fallback=None):
    for key in keys:
        if key in d:
            d = d[key]
        else:
            return fallback
    return d

def navigateDict(d, *keys):
    return navigateDictEx(d, keys)
Run Code Online (Sandbox Code Playgroud)

有关示例用法,请参阅摘要.

不管是否是Pythonic,这个功能可以减少冗余是一个坏主意的地方的重复.例如,更改示例中的一个路径组件需要在原始示例中将最多三个不同的值修改为一个,但在修改的示例中仅修改一个.鉴于我经常犯错误,这是一个巨大的胜利.

最后我问这个问题:标准库中有没有这样做,或者我需要在我的项目库中找到它的位置?

如果预计命中率将占据主导地位

brionius正确地指出捕捉KeyError将起作用:

try:
    print data[1]['i']['a']
except KeyError:
    print "Not found"
Run Code Online (Sandbox Code Playgroud)

这可能是我走的路; 这很简洁,减少了重复.然而,它确实反映了一个假设,即会有更多的命中而不是未命中.如果有更好的方式来反对我也想知道这一点.

Bri*_*ius 7

一种方法是这样做:

try:
    print data[1]['i']['a']
except KeyError:
    print "Not found!"
Run Code Online (Sandbox Code Playgroud)

这符合鸭子打字的精神.它可能会也可能不会那么快,因为我认为处理异常会带来一定的开销,但它肯定是"安全的".


Jor*_*ley 5

这样的解决方案很酷

https://twitter.com/raymondh/status/343823801278140417

>>> from collections import defaultdict
>>> infinite_defaultdict = lambda: defaultdict(infinite_defaultdict)
>>> d = infinite_defaultdict() 
>>> d['x']['y']['z'] = 10
>>> if d['x']['y']['z']: print d['x']['y']['z'] #better reflects that misses are common
Run Code Online (Sandbox Code Playgroud)