简体   繁体   中英

How to programmatically catch which command failed on a try block

I'm trying to get some data from an JSON API. I don't want all the data that the API returns so I wrote a method that reads all the data and returns a dictionary with the relevant fields. Sometimes though, some data are missing and I would like to replace the fields that are missing with an underscore. A sample of the method is like that;

return {
    'foo': data['foo'],
    'bar': data['bar']
 }

If a field is missing from the data, this throughs a KeyError. Is it possible to catch programmatically which field produced the error, in a single try-except block and not write a try-except block for every field?

try:
    ret_dict =  {
        'foo': data['foo'],
        'bar': data['bar']
    }
 except KeyError:
    ret_dict[thefailurekey] = '_'

instead of

ret_dict = {}
try:
    ret_dict['foo'] = data['foo']
except KeyError:
    ret_dict['foo'] = '_'
try:
    ret_dict['bar'] = data['bar']
except:
    ret_dict['bar'] = '_'

Thank you

You can probably get that information from the members of the KeyError exception object, but a simpler way would be to just use get() that will return a default value if the key is not there.

return {
    'foo': data.get('foo', '_'),
    'bar': data.get('bar', '_'),
 }

Another reason this is better than handling an exception is that you can only handle one exception. What happens if two keys are missing? And on top of that, ret_dict will not even be defined in your example because the code failed.

Instead of using try block, you can use dict.get(key, default_val)

For example:

ret_dict = dict(
    foo=data.get('foo', '-'),
    bar=data.get('bar', '-')
)

return ret_dict

Use .get method of dict :

def get_data(data):
    return {
        # If you want to accept falsy values from API:
        'foo': data.get('foo', '_'),

        # If you want to override falsy values from API:
        'bar': data.get('bar') or '_',
    }

.get returns its second argument ( None by default) if a dict doesn't have requested key, so it is always safe to use it in uncertain situations.

Example:

>>> data = {'foo': False, 'bar': False}
>>> get_data(data)
{'bar': '_', 'foo': False}

If you want to avoid the repetitiveness of typing .get(attr, '_') for each key, you can use a defaultdict , setting it to return _ when a key is trying to be accessed but missing.

from collections import defaultdict

data = {
    'foo': 'foo_value',
}

ret_dict = defaultdict(lambda: '_')
ret_dict.update(data)

print(ret_dict['foo'])  # 'foo_value'
print(ret_dict['bar'])  # '_'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM