我试图解析我从Web API获得的JSON响应。问题是JSON可以有不同的级别,这可以转换成字典的字典,并且偶尔会出现列表。 示例(这可行):
for r in json_doc['results']:
yield r.get('lastLoginLocation',{}).get('coordinates',{}).get('lat',{})
当词典列表在那里时,我可以做同样的事情吗?如果列表已填充,我希望从列表中的第一个字典返回指定的键值,或者返回' {}'如果列表为空。
示例(这不起作用)
yield r.get('profile',{}).get('phones',{})[0].get('default',{})
答案 0 :(得分:0)
很简单地在`get(' phones')中使用一个列表,默认为一个空dict,即:
yield r.get('profile',{}).get('phones',[{}])[0].get('default',{})
请注意,如果IndexError
为空列表,则仍会以r["profile"]["phones"]
为中断。你可以使用or
,即:
yield (r.get('profile',{}).get('phones',[{}]) or [{}])[0].get('default',{})
但是它变得非常混乱(并且没有充分的理由建立两个空的序列和列表),因此,对于更明确的代码,你可能会更好,参见Pankaj Singhal的回答。 / p>
答案 1 :(得分:0)
您的方法非常不理想,因为根词典中缺少的profile
键不会终止搜索,但会继续不必要的。显然,空字典中没有任何键。
您可以使用try/except
:
def get_value(container, keys=None)
if keys is None:
raise ValueError
for r in container:
item = r
for i in keys:
try:
item = item[i]
except (IndexError, KeyError):
yield {}
break
# finished cleanly
else:
yield item
get_value(json_doc['results'], keys=['profile', 'phones', 0, 'default'])
答案 2 :(得分:0)
这个get_nested
辅助函数可能就是你想要的。我过去在一些XML解析代码中使用了类似的技术。它删除了
通过模糊代码实际尝试实现的内容来实现。
from contextlib import suppress
def get_nested(list_or_dict, keys, default={}):
"""Get value from nested list_or_dict using keys. If the current
level is a dict, lookup the current key. If the current
level is a list, lookup current key in the first element of the
list. Return default for any errors.
"""
def get(item, key):
if hasattr(item, 'get') and key in item:
return item[key]
raise KeyError
for key in keys:
with suppress(KeyError):
list_or_dict = get(list_or_dict, key)
continue
with suppress(IndexError, KeyError):
list_or_dict = get(list_or_dict[0], key)
continue
break
else:
return list_or_dict
return default
您调用它的代码将是这样的:
for r in json_doc['results']:
yield get_nested(r, ('lastLoginLocation', 'coordinates', 'lat'))
yield get_nested(r, ('profile', 'phones', 'default'))