KAs
KAs

Reputation: 1868

return None if it throws exception in the middle of a statement in Python

I have multiple lines to decode some parameters from multiple big JSON files, they may have minor difference on the structure due to some branches are optional which may not exist in some files. The code is as below:

a = content['x'].findAll('div')[0]['y'].find(id='z').html.text
b = content['t'].findAll('a')[1].finaAll('b')[2]['y'].text
c = content['q'].find(id='f')[4].text
...

Since it may return None at any place, so it may throw exception when trying to populate value a, b, c, etc... How could U write a wrapper function which could act like below: when there's any exception thrown, just return None.

a = get_or_none(content['x'].findAll('div')[0]['y'].find(id='z').html.text)
b = get_or_none(content['t'].findAll('a')[1].finaAll('b')[2]['y'].text)
c = get_or_none(content['q'].find(id='f')[4].text)
...

Since there are too many variables like a, b and c, so I don't wanna write try..except for every line of my code. Any suggestions? Thanks!

Upvotes: 0

Views: 151

Answers (2)

Anton vBR
Anton vBR

Reputation: 18916

I might have been wrong with my comment. I was thinking of something like this actually. But this is quite far away from my "basic" knowledge. I just like to simplify problems - might be useful for someone but don't take it as the "best answer".

Example adopted from here: https://www.programiz.com/python-programming/decorator

def ordinary(string):
    return int(string)

# normal function
print(ordinary("2")) # returns 2

Now let's change that function:

# a function that enhances a function
def enhance(func):
    def inner(string):
        try:
            return func(string)
        except:
            return None
    return inner

# now let's enhance it assigning it to a variable name
# this is the 'decorate' part
get_or_none = enhance(ordinary)

# use new function
print(get_or_none("a")) # returns None
print(get_or_none("12")) # return 12

# old function will throw an error still
print(ordinary("a")) # throws an error

Upvotes: 0

Aran-Fey
Aran-Fey

Reputation: 43166

The problem with a = get_or_none(content['x'].findAll('div')[0]['y'].find(id='z').html.text) is that the get_or_none function can't catch exceptions thrown in content['x'].findAll(...), because that code is executed before get_or_none is even called.

To get around this, you have to delay the execution of this code until you're inside of get_or_none. This is easiest with a lambda:

a = get_or_none(lambda: content['x'].findAll('div')[0]['y'].find(id='z').html.text)

Now the code isn't executed until we call the lambda function. We can thus define get_or_none as:

def get_or_none(func):
    try:
        return func()
    except Exception:
        return None

Upvotes: 3

Related Questions