Python - 有没有优雅的方式在从json对象提取数据时避免大量的try/except块?

3 投票
5 回答
959 浏览
提问于 2025-04-16 22:20

我在寻找一些方法来写像 get_profile(js) 这样的函数,但不想用那些繁琐的 try/except 语句。

每次赋值都放在 try/except 里,因为有时候 json 字段可能不存在。如果能有一个优雅的解决方案,能把所有缺失的字段默认设置为 None,那我会很满意。虽然我已经为一些字段设置了默认值,比如 [] 等,但如果这样做能让整体代码看起来更简洁,那就更好了。

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

5 个回答

8
  1. 使用字典的 get(key[, default]) 方法。
  2. 这段代码可以生成一些基础代码,帮你省去更多麻烦。
8

把你所有的 try catch 代码块换成链式调用字典的 get(key [,default]) 方法。链中除了最后一次调用的 get 方法,前面的调用都应该设置默认值为 {}(空字典),这样后面的调用才能在一个有效的对象上进行。只有链中最后一次调用的 get 方法才应该使用你想查找的键的默认值。

想了解更多关于字典的信息,可以查看 Python 的官方文档:http://docs.python.org/library/stdtypes.html#mapping-types-dict

举个例子:

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

试试这样的做法...

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"}}},
    }
})

我有点冒险地假设你用的是一个字典,而不是一个列表,里面有一个键是0,不过... 你明白我的意思了。

撰写回答