我正在尝试解析我从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',{})
在`get('phones'(中使用一个空dict的列表,即默认值,即:
yield r.get('profile',{}).get('phones',[{}])[0].get('default',{})
请注意,如果r["profile"]["phones"]
是一个空列表,则仍然会与IndexError
中断。您可以使用or
,即:
yield (r.get('profile',{}).get('phones',[{}]) or [{}])[0].get('default',{})
但是它确实变得凌乱(并且没有充分的理由构建两个空的命令和列表(,因此您可能会更好地说明更明确的代码,cf pankaj singhal的答案。
您的方法非常卑鄙,因为root字典中缺少的 profile
键不会终止搜索,但在不必要的上继续进一步。显然在空的dict中不会有任何钥匙。
您可以使用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'])
此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'))