24

我正在使用 dict.get('keyword') 方法查询嵌套字典。目前我的语法是......

M = cursor_object_results_of_db_query

for m in M:
    X = m.get("gparents").get("parent").get("child")
    for x in X:
        y = x.get("key")

但是,有时“父”或“子”标签之一不存在,我的脚本失败。我知道使用get()我可以在表单的密钥不存在的情况下包含默认值...

get("parent", '') or
get("parent", 'orphan') 

但是,如果我包含任何我能想到的 , 或 empty ,则调用时链接Null失败,因为没有 method 。''.get("child")''.get("child")"".get()

try-except我现在解决这个问题的方法是在每个调用周围使用一堆顺序.get(""),但这似乎很愚蠢和不python - 有没有一种方法可以默认返回"skip""pass"仍然支持链接和智能失败,而不是深度-潜入不存在的键?

理想情况下,我希望这是对表单的列表理解:

[m.get("gparents").get("parent").get("child") for m in M]

.get("child")但是当缺席的父母导致调用终止我的程序时,这目前是不可能的。

4

4 回答 4

82

由于这些都是 pythondict并且您正在对它们调用dict.get()方法,因此您可以使用空dict来链接:

[m.get("gparents", {}).get("parent", {}).get("child") for m in M]

通过保留最后一个默认值,.get()您将退回到None. 现在,如果没有找到任何中间键,则链的其余部分将使用空字典查找内容,并以.get('child')return终止None

于 2013-01-23T16:32:26.603 回答
8

另一种方法是识别如果未找到密钥,则dict.get返回None。但是,None没有属性.get,所以它会抛出一个AttributeError

for m in M:
    try:
       X = m.get("gparents").get("parent").get("child")
    except AttributeError:
       continue

    for x in X:
        y = x.get("key")
        #do something with `y` probably???

就像 Martijn 的回答一样,这并不能保证它X是可迭代的(非None)。虽然,您可以通过使get链中的最后一个默认返回一个空列表来解决这个问题:

 try:
    X = m.get("gparents").get("parent").get("child",[])
 except AttributeError:
    continue

最后,我认为这个问题的最佳解决方案可能是使用reduce

try:
    X = reduce(dict.__getitem__,["gparents","parent","child"],m)
except (KeyError,TypeError):
    pass
else:
    for x in X:
       #do something with x

这里的好处是您可以get根据引发的异常类型知道是否有任何 s 失败。a 可能get返回错误的类型,然后你得到 a TypeError。但是,如果字典没有键,它会引发一个KeyError. 您可以单独或一起处理这些问题。无论哪种方式最适合您的用例。

于 2013-01-23T16:38:38.377 回答
5

使用一个小的辅助函数怎么样?

def getn(d, path):
    for p in path:
        if p not in d:
            return None
        d = d[p]
    return d

接着

[getn(m, ["gparents", "parent", "child"]) for m in M]
于 2013-01-23T16:41:41.363 回答
4

我意识到我有点迟到了,但这是我在遇到类似问题时提出的解决方案:

def get_nested(dict_, *keys, default=None):
    if not isinstance(dict_, dict):
        return default
    elem = dict_.get(keys[0], default)
    if len(keys) == 1:
        return elem
    return get_nested(elem, *keys[1:], default=default)

例如:

In [29]: a = {'b': {'c': 1}}
In [30]: get_nested(a, 'b', 'c')
Out[30]: 1
In [31]: get_nested(a, 'b', 'd') is None
Out[31]: True
于 2016-01-23T00:13:17.983 回答