sente
sente

Reputation: 2377

Python - is there an elegant way to avoid dozens try/except blocks while getting data out of a json object?

I'm looking for ways to write functions like get_profile(js) but without all the ugly try/excepts.

Each assignment is in a try/except because occasionally the json field doesn't exist. I'd be happy with an elegant solution which defaulted everything to None even though I'm setting some defaults to [] and such, if doing so would make the overall code much nicer.

def get_profile(js):
    """ given a json object, return a dict of a subset of the data.
        what are some cleaner/terser ways to implement this?

        There will be many other get_foo(js), get_bar(js) functions which
        need to do the same general type of thing.
    """

    d = {}

    try:
        d['links'] = js['entry']['gd$feedLink']
    except:
        d['links'] = []

    try:
        d['statisitcs'] = js['entry']['yt$statistics']
    except:
        d['statistics'] = {}

    try:
        d['published'] = js['entry']['published']['$t']
    except:
        d['published'] = ''

    try:
        d['updated'] = js['entry']['updated']['$t']
    except:
        d['updated'] = ''

    try:
        d['age'] = js['entry']['yt$age']['$t']
    except:
        d['age'] = 0

    try:
        d['name'] = js['entry']['author'][0]['name']['$t']
    except:
        d['name'] = ''

    return d

Upvotes: 3

Views: 970

Answers (5)

Ishpeck
Ishpeck

Reputation: 2041

Try something like...

import time

def get_profile(js):
    def cas(prev, el):
        if hasattr(prev, "get") and prev:
            return prev.get(el, prev)
        return prev
    def getget(default, *elements):
        return reduce(cas, elements[1:], js.get(elements[0], default))

    d = {}
    d['links'] = getget([], 'entry', 'gd$feedLink')
    d['statistics'] = getget({}, 'entry', 'yt$statistics')
    d['published'] = getget('', 'entry', 'published', '$t')
    d['updated'] = getget('', 'entry', 'updated', '$t')
    d['age'] = getget(0, 'entry', 'yt$age', '$t')
    d['name'] = getget('', 'entry', 'author', 0, 'name' '$t')
    return d

print get_profile({
    'entry':{
        'gd$feedLink':range(4),
        'yt$statistics':{'foo':1, 'bar':2},
        'published':{
            "$t":time.strftime("%x %X"),
        }, 
        'updated':{
            "$t":time.strftime("%x %X"),
        },
        'yt$age':{
            "$t":"infinity years",
        },
        'author':{0:{'name':{'$t':"I am a cow"}}},
    }
})

It's kind of a leap of faith for me to assume that you've got a dictionary with a key of 0 instead of a list but... You get the idea.

Upvotes: 3

psr
psr

Reputation: 2900

  1. Use get(key[, default]) method of dictionaries
  2. Code generate this boilerplate code and save yourself even more trouble.

Upvotes: 8

Alex Q
Alex Q

Reputation: 3260

Replace each of your try catch blocks with chained calls to the dictionary get(key [,default]) method. All calls to get before the last call in the chain should have a default value of {} (empty dictionary) so that the later calls can be called on a valid object, Only the last call in the chain should have the default value for the key that you are trying to look up.

See the python documentation for dictionairies http://docs.python.org/library/stdtypes.html#mapping-types-dict

For example:

d['links']     = js.get('entry', {}).get('gd$feedLink', [])
d['published'] = js.get('entry', {}).get('published',{}).get('$t', '')

Upvotes: 8

waffle paradox
waffle paradox

Reputation: 2775

Two possible solutions come to mind, without knowing more about how your data is structured:

if k in js['entry']:
    something = js['entry'][k]

(though this solution wouldn't really get rid of your redundancy problem, it is more concise than a ton of try/excepts) or

js['entry'].get(k, []) # or (k, None) depending on what you want to do

A much shorter version is just something like...

for k,v in js['entry']:
    d[k] = v

But again, more would have to be said about your data.

Upvotes: 1

John Jiang
John Jiang

Reputation: 11489

You need to familiarise yourself with dictionary methods Check here for how to handle what you're asking.

Upvotes: 2

Related Questions