我正在从外部来源阅读字典,让我们说
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', {})
答案 0 :(得分:2)
默认情况下,如果密钥不存在,.get()
将返回None
。在你的情况下,你将返回一个空字典。
现在,我不知道提出了什么错误,但我确信它来自get_stuff(article)
,而不是你的列表理解。
您有几种方法可以解决这个问题:
修改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
在列表推导中添加过滤器:
[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')