What is the pythonic way to access nested dicts without NoneType errors

删除回忆录丶 提交于 2019-12-06 13:55:24

The most Pythonic way would be simply to catch the KeyError:

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

This is simple, obvious, and immediately understandable to a Python programmer.

How do you feel about something like this

if 'caption' in post:
    caption = post['caption']['text']

But it also starts to break down

if 'images' in post and 'standard_resolution' in post['images']:
    image_url = post['images']['standard_resolution']['url']

So I think the most Pythonic way is to just ask for forgiveness and not permission

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

Python 3.4 and newer versions contains a contextlib context manager suppress, which is for exactly this kind of thing. Suppressing specific errors when you know in advance they may happen and your code can handle it.

from contextlib import suppress

sample = {'foo': 'bar'}

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

Will prevent the KeyError from being raised.

So for accessing getting a deeply nested dictionary value, you can use suppress like this.

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

I'd create a custom dict subclass, and then just address that:

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

You could either do a custom init to handle nested dicts as another instance of SafeDict ( which would allow you to pass them around ) or you could use testing (or a try/except block) to prevent KeyErrors

also, you could just make it an object class, overload __getattr__ , and then handle things with dot notation. i tend to prefer that approach ( I first saw this in the Pylons framework )

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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!