什么是Pythonic方式来访问没有NoneType错误的嵌套字典

问题描述:

我有一个深嵌套字典(解码从JSON,从Instagram的API)。 我最初的代码是这样的:什么是Pythonic方式来访问没有NoneType错误的嵌套字典

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

但是,这将抛出一个NoneType或KeyError异常错误,如果“字幕”键或“文本”项不存在。

于是我想出了这一点:

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

其中一期工程,但我不知道它的风格。举例来说,如果我将此技术向更深嵌套的属性,我试图找回之一,它看起来很丑陋:

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

是否还有更好的,更Python,这样写?我的目标是检索数据,如果存在的话,但不保留执行,如果它不存在。

谢谢!

+0

为什么你不能只是发现异常? – Cairnarvon 2013-02-23 03:42:18

+0

我可以。我想是因为我拉〜7键,我不想尝试/除了7次。 – 2013-02-23 03:48:31

+1

相关:[Python:使用列表中的项目更改嵌套字典的字典值](http://*.com/questions/11918852/python-change-values-in-dict-of-nested-dicts-using-项目在列表中) – jfs 2013-02-23 03:55:37

最Pythonic的方式将只是为了赶上KeyError

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

这对于Python程序员来说很简单,显而易见并且可以立即理解。

+1

请不要将'try:'和'except:'的主体放在与其各自介绍相同的行上。这是[PEP 8](http://www.python.org/dev/peps/pep-0008/)的Definitely Nots中的一个,它本身就是纯音乐。 – Cairnarvon 2013-02-23 03:55:05

+2

已修复,对PEP 8表示歉意。 – nneonneo 2013-02-23 03:56:21

+0

有没有办法将这个推广到多个键?例如如果我想检索'caption.text',但也''images.standard_resolution.url'和'user.username'和其他一些,我必须做尝试/除了块? – 2013-02-23 04:05:40

你怎么看待这样的事情

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化的方法是只ask for forgiveness and not permission

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

不要使用光秃秃的,虽然或有趣的坏事情会发生。 (例如'KeyboardInterrupt'被吞咽) – nneonneo 2013-02-23 03:45:52

+0

对不起,已经修好了。 – Ric 2013-02-23 03:46:57

我想创建一个自定义字典的子类,然后只是解决:

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 

你既可以做一个自定义初始化处理嵌套类型的字典作为SafeDict的另一个实例(这将让你通过它们)或者你可以使用测试(或者一个try/except块)来防止KeyErrors,也可以使它成为一个对象类,重载__getattr__,然后用点符号来处理事情。我倾向于选择这种做法(我第一次在塔框架看到这个)

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 
+0

'post'字典来自simplejson,我不知道如何让simplejson返回SafeDict,或将标准字典转换为SafeDict。 – 2013-02-23 04:03:08

+0

您的'__getitem __()'代码会比'return self.get(k)'更简单(您大多正在重写'get()'方法)。无论如何,这确实回答了这个问题,因为即使'a = SafeDict({'a':SafeDict({'b':'b'})})''''a''c'] ['d']'这是问题要求解决的问题。 – EOL 2013-02-23 04:04:53

+0

如果你退后一秒......你会注意到调用AnyClass(yourdict)真正调用了'AnyClass .__ init__',并将字典作为kwargs。如果你从'dict'继承了一个类,这些kwargs就成为了字典。如果您从对象继承,则可以使用__init__获得乐趣。个人而言,我可能会用对象符号去。它使得api编程更容易。 – 2013-02-23 04:06:38

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