【问题标题】:Chained, nested dict() get calls in python链式嵌套 dict() 在 python 中获取调用
【发布时间】:2013-01-07 04:59:36
【问题描述】:

我正在使用 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') 

但如果我包含任何Null'' 或我能想到的空,则在''.get("child") 上调用时,链接的.get("child") 会失败,因为"" 没有方法.get()

我现在解决这个问题的方法是在每个.get("") 调用周围使用一堆连续的try-except,但这似乎很愚蠢和不符合标准——有没有办法默认返回"skip" 或@987654337 @ 或者仍然支持链接和智能失败的东西,而不是深入研究不存在的键?

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

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

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

【问题讨论】:

标签: python dictionary list-comprehension


【解决方案1】:

由于这些都是 python dicts 并且你正在对它们调用 dict.get() 方法,你可以使用一个空的 dict 来链接:

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

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

【讨论】:

    【解决方案2】:

    另一种方法是识别如果未找到密钥,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
    

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

    【讨论】:

    • 哦,我知道你在那里做了什么。你必须在那里使用你的reduce() sans lambda! :-P
    • @MartijnPieters -- 自从前几天我把它煮熟后,我就一直渴望使用它;-)。
    【解决方案3】:

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

    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]
    

    【讨论】:

      【解决方案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
      

      【讨论】:

      • 顺便说一句,这个def get_nested(dict_, *keys, default=None) 仅适用于python 3(*keys 之后的关键字default arg
      猜你喜欢
      • 1970-01-01
      • 2020-07-22
      • 1970-01-01
      • 2014-09-03
      • 2018-04-26
      • 1970-01-01
      • 2014-04-01
      • 2022-07-08
      • 2016-06-13
      相关资源
      最近更新 更多