给定一个带有许多键(属性?)的json对象,如:
[{'name': 'Bob', 'infos': {'spam': 'eggs', 'foo': 'bar'}},
{'name': 'Tom'},
{'name': 'Lisa', 'infos': {'spam': 'qux', 'foo': 'baz'}}
...]
我希望使用列表推导来过滤掉entry['infos']['spam'] == 'eggs'
如果可能的话,我更喜欢列表理解,但到目前为止,我唯一的解决方案是使用多个.get()
s,最远的树下最远的那些(以避免KeyError
通过在语句False
到达之前发出声明{。}}。
例如,
# Will obviously fail with KeyError
[each for each in my_json if each['infos']['spam'] == 'eggs']
# Works but requires a separate / additional `.get()`, and only works
# because it is returning False before it evaluates all conditions
[each for each in my_json if each.get('infos') and each.get('infos').get('spam') == 'eggs']
# Fails as all conditions will be evaluated before running
[each for each in my_json if all([each.get('infos'), each.get('infos').get('spam') == 'eggs'])]
# Not a list comprehension, but concise... and also doesn't work
filter(lambda x: x['infos']['spam'] == 'eggs', my_json)
有没有更好的方法来过滤我的json响应?我问的原因是一些API返回json对象,其中感兴趣的键深向下...并且必须使用像each.get('a') and each['a'].get('b') and each['a']['b'].get('c') == 'd'
这样的东西似乎很难用来验证each['a']['b']['c'] == 'd'
我想我总是可以使用try
except KeyError
。
mylist = []
for each in my_json:
try:
if each['infos']['spam'] == 'eggs':
mylist.append(each)
except KeyError:
pass
我是否缺少一个明显的解决方案(最好是在python3标准库中),以消除所有工作解决方案中的冗余?
答案 0 :(得分:5)
如果该密钥不存在任何项目,您可以指定get
的默认值,因此您可以使用
[each for each in my_json if each.get('infos', {}).get('spam') == 'eggs']
第一个获取get('infos', {})
指定一个空的dict作为默认值,以便第二个获胜失败。
此处为filter
>>> filter(lambda x: x.get('infos', {}).get('spam') == 'eggs', my_json)
[{'infos': {'foo': 'bar', 'spam': 'eggs'}, 'name': 'Bob'}]
请注意,如果" infos"存在于外部词典中,但本身并不是一个词典。
更健壮的方法是定义过滤函数:
>>> def wonderful_spam(x):
... try:
... return x['infos']['spam'] == 'eggs'
... except (KeyError, TypeError):
... return False
...
>>> filter(wonderful_spam, my_json)
[{'infos': {'foo': 'bar', 'spam': 'eggs'}, 'name': 'Bob'}]
>>> [x for x in my_json if wonderful_spam(x)]
[{'infos': {'foo': 'bar', 'spam': 'eggs'}, 'name': 'Bob'}]