Python从字典中假设值的最佳方法是什么?

时间:2016-07-12 01:47:42

标签: python dictionary

我正在从外部来源阅读字典,让我们说

data = {'name': 'James', 'gender': 'male'}

有时

data = {'name': 'James', 'gender': 'male', 'article': {'title':'abc'}}

有时

data = {'name': 'James', 'gender': 'male', 'article': None}

我知道当我不确定数据中是否存在.get(key, default)时,我可以使用articles

articles = data.get('article', {}).get('title')

但有时,它们会为元素提供None值,因此上述内容不起作用并导致错误,并且需要变为:

articles = data.get('article') or {}

但是这需要我把它分成2个语句,而不是像前面提到的那样用链接来获取文章中的值。

是否有更优雅的方式来做到这一点,例如:

data.get('article', {}, ignore=[None])

data.get_ignore_none('article', {})

5 个答案:

答案 0 :(得分:2)

默认情况下,如果密钥不存在,.get()将返回None。在你的情况下,你将返回一个空字典。

现在,我不知道提出了什么错误,但我确信它来自get_stuff(article),而不是你的列表理解。

您有几种方法可以解决这个问题:

  1. 修改get_stuff以使其直接获取值,而不是每个元素。这样,您只是传递它[get_stuff(value) for value in data.get('articles')]。现在,在get_stuff中,您只需执行此操作:

    def get_stuff(foo):
      if not foo:
        return None
      for item in foo:
        do stuff
      return normal_results
    
  2. 在列表推导中添加过滤器:

    [get_stuff(foo) for foo in data.get('articles') if data.get('articles')]
    

答案 1 :(得分:2)

在这种情况下,使用例外来提前爆发并没有错。无论数据是什么,我都假设你想要标题值,或者无。以下函数将起作用(对于Python 3)。

def get_title(d):
    try:
        return data.get("article").get("title")
    except AttributeError:
        return None

如果外部字典的值为None,或者默认情况下会引发您刚刚捕获的None对象的AttributeError。

答案 2 :(得分:1)

首先,您似乎认为使用or表达式从data.get('article')中丢弃false-y results只能在以下两个语句中完成:

temp = data.get('article') or {}
articles = temp.get("title")

但是你可以在第一个表达式周围加上括号,并直接在它的返回值上调用.get("title")

articles = (data.get('article') or {}).get("title")

但是当我'article'丢失或None时,我觉得这不是特别具有可读性或效率,那么您正在创建新的映射并不必要地检查"title"

一种可能的解决方案是使用如下函数:

def nested_get(mapping, *keys):
    """gets a value from a nested dictionary,
if any key along the way is missing or None then None is returned
will raise an AttributeError if a value in the chain is not a dictionary (support the .get method)"""
    current = mapping
    for item in keys:
        current = current.get(item)
        if current is None:
            return None
    return current

然后,如果nested_get(data, "article", "title")为无或缺失,您可以data["article"]["title"]尝试获取data["article"]而不会抛出错误。

我使用以下代码对此进行了测试:

test_cases = [{'name': 'James', 'gender': 'male'},
              {'name': 'James', 'gender': 'male', 'article': {'title':'abc'}},
              {'name': 'James', 'gender': 'male', 'article': None}]

for case in test_cases:
    print(case)
    print(nested_get(case,"article","title"))
    print()

#the follwing will raise an error since mapping["a"] would need to be a dict
nested_get({"a":5}, "a","b")

答案 3 :(得分:0)

这个怎么样

>>> data = {1:(42,23)}
>>> [x for x in data.get(1) or []]
[42, 23]
>>> [x for x in data.get(32) or []]
[]

使用or更改为默认值,以防您获得None或eval为false的内容

修改

以同样的方式,or和括号可以在一行中获得所需的输出

articles = (data.get('article') or {}).get('title')

只是你处理了所有3个案件。

您也可以定义get_ignore_none,例如

def get_ignore_none(data_dict, key, default=None):
    if key in data_dict:
        value = data_dict[key]
        return value if value is not None else default
    return default

答案 4 :(得分:0)

由于您是从外部源加载此数据,因此只要加载它,一个选项就是预处理步骤

from collections import Mapping

def remove_none(d):
    for k, v in d.items():
        if v is None:
            del d[k]
        if isinstance(v, Mapping):
            remove_none(v)

data = load_data_from_somewhere()
remove_none(data)

现在,您可以在任何地方使用get

articles = data.get('article', {}).get('title')