我有一个深度嵌套的dict(从json解码,从instagramapi解码)。我最初的代码是这样的:
caption = post['caption']['text']
但如果"caption"键或"text"键不存在,则会引发NoneType或KeyError错误。
所以我想出了这个:
caption = post.get('caption', {}).get("text")
这是有效的,但我不确定它的风格。例如,如果我将这种技术应用于我试图检索的一个更深嵌套的属性,它看起来很难看:
image_url = post.get('images',{}).get('standard_resolution',{}).get('url')
有没有更好、更像蟒蛇的方式来写这篇文章?我的目标是检索数据,如果数据在那里,但如果数据不在那里,就不要阻碍执行。
谢谢!
最Python的方法就是简单地捕获KeyError
:
try:
caption = post['caption']['text']
except KeyError:
caption = None
对于Python程序员来说,这是简单、显而易见的,并且可以立即理解。
Python 3.4及更新版本包含一个contextlib上下文管理器suppress
,它正是用于这类事情的。当你事先知道可能会发生特定错误,并且你的代码可以处理时,就可以抑制这些错误
from contextlib import suppress
sample = {'foo': 'bar'}
with suppress(KeyError):
print(sample['baz'])
将阻止KeyError
被提起。
因此,为了访问获取深度嵌套的dictionary值,可以像这样使用suppress
。
value = None
with suppress(KeyError):
value = data['deeply']['nested']['dictionary']['key']
你觉得这个怎么样
if 'caption' in post:
caption = post['caption']['text']
但它也开始破坏
if 'images' in post and 'standard_resolution' in post['images']:
image_url = post['images']['standard_resolution']['url']
所以我认为最Python的方式是请求原谅,而不是允许
try:
image_url = post['images']['standard_resolution']['url']
except KeyError:
image_url = None
我会创建一个自定义dict子类,然后只处理它:
class SafeDict(dict):
def __getitem__(self,k):
if k in self:
return dict.__getitem__(self,k)
return None
a = SafeDict({'a':'a'})
print a['a']
>> a
print a['b']
>> None
您可以执行自定义init以将嵌套dict作为SafeDict的另一个实例来处理(这将允许您传递它们),也可以使用测试(或try/except块)来防止KeyErrors
此外,您可以将它作为一个对象类,重载__getattr__
,然后用点表示法处理事情。我更喜欢这种方法(我第一次在Pylons框架中看到这种方法)
class AttributeSafeObject(object):
def __init__(self,**kwargs):
for key in kwargs:
setattr(self,key,kwargs[key])
def __getattr__(self, name):
try:
return object.__getattribute__(self,name)
except AttributeError:
return None
post = AttributeSafeObject({'a':'a'})
print post.a
>> a
print post.title
>> None