在没有NoneType错误的情况下访问嵌套dicts的pythonic方法是什么

时间:2013-02-23 03:36:42

标签: python dictionary styles nonetype keyerror

我有一个深层嵌套的dict(从json解码,来自instagram api)。 我的初始代码是这样的:

caption = post['caption']['text']

但如果“标题”键或“文本”键不存在,则会抛出NoneType或KeyError错误。

所以我想出了这个:

caption = post.get('caption', {}).get("text")

哪个有效,但我不确定它的风格。例如,如果我将这种技术应用于我试图检索的更深层次的嵌套属性之一,它看起来很丑陋:

image_url = post.get('images',{}).get('standard_resolution',{}).get('url')

有没有更好,更pythonic的方式来写这个?我的目标是检索数据(如果有的话),但如果数据不存在则不会阻止执行。

谢谢!

4 个答案:

答案 0 :(得分:10)

最恐怖的方式就是捕捉KeyError

try:
    caption = post['caption']['text']
except KeyError:
    caption = None

这对Python程序员来说简单明了,并且可以立即理解。

答案 1 :(得分:2)

你觉得这样的事情

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']

所以我认为最恐怖的方式就是ask for forgiveness and not permission

try:
    image_url = post['images']['standard_resolution']['url']
except KeyError:
    image_url = None

答案 2 :(得分:1)

Python 3.4和更新版本包含一个contextlib上下文管理器suppress,它正是为了这种事情。当您提前知道它们可能发生并且您的代码可以处理它时,可以抑制特定错误。

from contextlib import suppress

sample = {'foo': 'bar'}

with suppress(KeyError):
    print(sample['baz'])

会阻止KeyError被提升。

因此,要访问获取深层嵌套的字典值,您可以使用suppress这样的内容。

value = None
with suppress(KeyError):
    value = data['deeply']['nested']['dictionary']['key']

答案 3 :(得分:-1)

我创建了一个自定义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 来处理嵌套的dicts作为另一个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