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

Posted

技术标签:

【中文标题】Python安全字典导航,正确的方式【英文标题】:Python safe dict navigation, The Right Way 【发布时间】:2013-08-25 11:41:26 【问题描述】:

TLDR 总结

我编写了一个函数navigateDict,它在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"

大致相当

found = navigateDict(data, 1, 'i', 'a')
if found is not None:
    print found
else:
    print "Not found"
标准库中是否有类似的内容? 有没有更惯用的方法来做同样的事情? 任何需要多次输入任何路径组件键的响应都可能是非响应。

其他细节

实现如下:

# 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)

查看摘要以了解示例用法。

不管是否是 Python 的,这个函数在冗余是一个坏主意的地方减少了重复。例如,在示例中更改一个路径组件需要将最多三个不同的值修改为原始示例中的一个,但在修改后的示例中只需要一个。鉴于我经常犯错,这是一个巨大的胜利。

最终我要问的是:标准库中有什么东西可以做到这一点,还是我需要在我的项目库中为它找到一个位置?

如果预期命中率高于未命中率

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

try:
    print data[1]['i']['a']
except KeyError:
    print "Not found"

这可能是我要走的路;它非常简洁,减少了重复。然而,它确实反映了一个假设,即命中比未命中要多。如果有更好的假设相反的方法,我也想知道。

【问题讨论】:

【参考方案1】:

一种方法如下:

try:
    print data[1]['i']['a']
except KeyError:
    print "Not found!"

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

【讨论】:

不错的选择。不过,为了让对话继续进行,假设我预计失误多于命中。【参考方案2】:

这样的解决方案很酷

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

【讨论】:

不错!只是想想办法制作一个“递归”的默认字典。唯一的缺点是只访问字典的元素就会用一个infinite_defaultdict 对象填充它。 它也不适用于现有的dictd.update(data) 来自现有的 dict data 不会进行深层复制,因此错过仍然会导致 KeyError。将空值强制为 None 对我来说也很重要,但这更多是个人问题...... 是的,它必须替换数据字典,而不仅仅是从中更新,或者您必须找出一些方案来从现有字典中手动填充它(可能不是太难,但是嗯) (澄清一下,一般来说,生成字典的代码不会是我的代码。)【参考方案3】:

游戏迟到了几年,但对于任何偶然发现这一点的人来说,似乎仍然没有一种本地、流畅的方式来安全地导航 Python 字典。

输入RestResponse:

“RestResponse 旨在成为一个流畅的 python 对象,用于与 RESTful JSON API 交互”

这个库包含一个 NoneProp 对象,允许安全地导航(和构建)JSON 数据结构。

>>> import RestResponse
>>> data = RestResponse.parse()
>>> data.property.is_none
None
>>> bool(data.property.is_none)
False
>>> isinstance(data.property.is_none, RestResponse.NoneProp)
True
>>> data.property.is_none = None
>>> isinstance(data.property.is_none, RestResponse.NoneProp)
False
>>> print data.pretty_print()

    "property": 
        "is_none": null
    

【讨论】:

以上是关于Python安全字典导航,正确的方式的主要内容,如果未能解决你的问题,请参考以下文章

以安全的方式从字典数据创建表

Python递归集合值排列字典

将 Python argparse.Namespace() 视为字典的正确方法是啥?

在 Python 中使用 None 值删除字典中键的正确方法

Python从嵌套字典中提取正确的数据

Python元组集和字典