Minion Jim
Minion Jim

Reputation: 1279

Error handling for list comprehension in Python

Is there a way to handle errors in a python list comprehension. Preferably I would have something like this where the last two values are represented by None:

values = [try i ["row"] except KeyError None for i in [{"row" : 1}, {"Row" : 0}, {}]]

This throws a syntax error and the only way I can do it is:

values = []
for i in [{"row" : 1}, {"Row" : 0}, {}]:
    try: values.append (i ["row"])
    except KeyError: values.append (None)

I hope there is a more 'neat' way of doing this because the current solution is not preferable due to having to append to a blank list when a list comprehension does this in such a nice way!

Upvotes: 2

Views: 596

Answers (3)

abarnert
abarnert

Reputation: 365945

You can't handle exceptions directly in a list comprehension, because try is a statement, not an expression.

However, you can abstract the try out into a separate function:

def tryirow(i):
    try: return i["row"]
    except KeyError: return None

values = [tryirow(i) for i in [{"row" : 1}, {"Row" : 0}, {}]]

Of course in this case, as Jean-François Fabre's answer implies, you've just reimplemented the built-in dict.get method:

values = [i.get("row") for i in [{"row" : 1}, {"Row" : 0}, {}]]

But this shows how you can solve similar problems more generally: if there's a function that does what you want, call it; if not, write it.


And of course sometimes, "write out a for statement" is actually the right answer. Not everything should be written as a list comprehension, even many things that can. I don't think that's relevant here, but it's worth keeping in mind.


There was actually a proposal to add a try expression just like the one you're trying to write, PEP 463. Why was it rejected? Because almost all of the use-cases were "get-with-default-fallback" cases where the function you want already exists (like dict.get) or should exist. Nobody could come up with a common use case that wasn't better written with a separate function or an expanded-out for statement.

In a brand new language, I think it would make more sense to have a try expression and not have methods like dict.get, but in a language that already had dict.get for over a decade before anyone suggested a try expression (and almost two decades before anyone put together a concrete proposal), that would be a bad change to make.

Upvotes: 1

niraj
niraj

Reputation: 18218

You can also check if key is dictionary in list comprehension and return None if it is not present:

key = 'row'
values = [i[key] if key in i else None for i in [{"row" : 1}, {"Row" : 0}, {}]]

Upvotes: 1

Jean-François Fabre
Jean-François Fabre

Reputation: 140276

you cannot catch an exception from a list comprehension (How can I handle exceptions in a list comprehension in Python?). But given what you want to do you could use get:

values = [i.get("row") for i in [{"row" : 1}, {"Row" : 0}, {}]]

if the key isn't found in the dictionary get returns None, exactly what you're looking for (it can return anything you want, just by passing the default value as second argument, see Why dict.get(key) instead of dict[key]?)

Upvotes: 3

Related Questions