4

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

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

但是,如果 'caption' 键或 'text' 键不存在,则会引发 NoneType 或 KeyError 错误。

所以我想出了这个:

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

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

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

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

谢谢!

4

4 回答 4

11

最 Pythonic 的方法是简单地捕捉KeyError

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

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

于 2013-02-23T03:43:13.020 回答
3

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']
于 2017-08-25T04:00:26.030 回答
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']

所以我认为最 Pythonic 的方式就是请求宽恕而不是许可

try:
    image_url = post['images']['standard_resolution']['url']
except KeyError:
    image_url = None
于 2013-02-23T03:38:54.513 回答
-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

您可以执行自定义初始化以将嵌套字典作为 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
于 2013-02-23T03:58:18.447 回答