How to handle exceptions in a list comprehensions?
There is no built-in expression in Python that lets you ignore an exception (or return alternate values &c in case of exceptions), so it's impossible, literally speaking, to "handle exceptions in a list comprehension" because a list comprehension is an expression containing other expression, nothing more (i.e., no statements, and only statements can catch/ignore/handle exceptions).
Function calls are expression, and the function bodies can include all the statements you want, so delegating the evaluation of the exception-prone sub-expression to a function, as you've noticed, is one feasible workaround (others, when feasible, are checks on values that might provoke exceptions, as also suggested in other answers).
The correct responses to the question "how to handle exceptions in a list comprehension" are all expressing part of all of this truth: 1) literally, i.e. lexically IN the comprehension itself, you can't; 2) practically, you delegate the job to a function or check for error prone values when that's feasible. Your repeated claim that this is not an answer is thus unfounded.
Python exception handling in list comprehension
try:
[plot_pdf(f) for f in file_list] # using list comprehensions
except:
print ("Exception: ", sys.exc_info()[0])
continue
If plot_pdf(f)
throws an error during execution of comprehension, then, it is caught in the except
clause, other items in comprehension won't be evaluated.It is not possible to handle exceptions in a list comprehension, for a list comprehension is an expression containing other expression, nothing more (i.e. no statements, and only statements can catch/ignore/handle exceptions).
More here.Function calls are expression, and the function bodies can include all
the statements you want, so delegating the evaluation of the
exception-prone sub-expression to a function, as you've noticed, is
one feasible workaround (others, when feasible, are checks on values
that might provoke exceptions, as also suggested in other answers).
Raising an exception in a list comprehension: invalid syntax
Syntax
From a syntaxic point of view, your answer is in the full grammar spec.The raise
terminal only appears in rules derived from stmt
(statement):
stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: (... | flow_stmt | ...)
flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
raise_stmt: 'raise' [test ['from' test]]
Whereas the first part of a list comprehension is a test
(boolean or expression) or a star_expr
(*expr
):atom: ... | '[' [testlist_comp] ']' | ...
testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
The point is there is no way a statement can be derived from the (test|star_expr)
(left part of a list comprehension). Hence, your expression is syntactically wrong.Semantic
As pointed by @Neb in a comment, a list comprehension trying to return araise
does not make sense.You probably remember that print
was a statement in Python 2 and became a function in Python 3:
Python 2:
>>> [print(1) for _ in range(1)]
File "<stdin>", line 1
[print(1) for _ in range(1)]
^
SyntaxError: invalid syntax
Python 3:>>> [print(1) for _ in range(1)]
1
[None]
The list comprehension is now syntactically correct. Similarly, no syntaxic rule prevents you from writing this:>>> def raiser(): raise ValueError('URI must be URL-encoded, ASCII only!')
...
>>> def redirect(uri): [raiser() for c in uri if not (32 <= ord(c) <= 127)]
...
>>> redirect("abc")
>>> redirect("éàç")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in redirect
File "<stdin>", line 1, in <listcomp>
File "<stdin>", line 1, in raiser
ValueError: URI must be URL-encoded, ASCII only!
But the semantic remains unclear: do you want to perform an action (ie use a side effect from a function), or to build a list? Remember that list comprehensions are a borrowing to functional langages, expecially Haskell I think. Hence, they are not here to perform actions.I quote @Mark Ransom comment to an answer to the "Is it Pythonic to use list comprehensions for just side effects?" question:
I use this rule of thumb: avoid any side effects in list comprehensions, even if you use the result.I would go even further and state that side effects inside a list comprehension are unusual, unexpected, and therefore evil, even if you're using the resulting list when you're done. – Mark Ransom
Error handling for list comprehension in Python
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]?) Can you embed a try in a Python list comprehension?
No, you can't. You can put only for
loops, if
's and else
's.
What you can do, though, is use .get()
, which never throws a KeyError:
my_list = [my_dict.get("some_key", 0) for my_dict in my_list]
The second argument is the default value in case the key does not exist. If you don't specify a default, the default default is None. Python list comprehension: Skip elements that raise exception
I think your first solution is clear, and that's the most important thing in python. Alternatively, how about a generator instead of a comprehension?
def try_div_itr(itr):
for elem in itr:
try:
yield 1 / elem
except ZeroDivisionError:
pass
result = list(try_div_itr([-2, -1, 0, 1, 2]))
You could even generalise this
def try_itr(func, itr, *exceptions, **kwargs):
for elem in itr:
try:
yield func(elem, **kwargs)
except exceptions:
pass
x = [random.choice([0, 1]) for _ in range(100_000)]
%timeit [i for i in (try_div(i) for i in x) if i is not None]
42.6 ms ± 109 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit [i for i in [try_div(i) for i in x] if i is not None]
36.3 ms ± 154 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit list(try_div_itr(x))
25.3 ms ± 85.1 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit list(try_itr(lambda i: 1/i, x, ZeroDivisionError))
34.7 ms ± 113 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
# but expect generic method to be slower anyway
%timeit list(try_itr((1).__truediv__, x, ZeroDivisionError))
28.7 ms ± 118 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
# remove lambda abstraction for speed
Using list comprehensions and exceptions?
List comprehensions are a syntactically concise way to create a list based on some existing list—they're not a general-purpose way of writing anylets say i want to the raise an exception when a required value is missing, with the value that it is missing. How can i do that using list comprehension?
for
-loop in a single line. In this example, you're not actually creating a list, so it doesn't make any sense to use a list comprehension. How to handle exceptions in dictionary comprehension
You can test for 0
with an inline if
:
lengths[k] / v if v != 0 else 0
directly in the comprehension
Related Topics
How to Reverse a Dictionary That Has Repeated Values
Scipy Curve_Fit Doesn't Like Math Module
What Does 'Wb' Mean in This Code, Using Python
Cannot Redirect Output When I Run Python Script on Windows Using Just Script's Name
Basic Program to Convert Integer to Roman Numerals
Writing Unit Tests in Python: How to Start
How May I Override the Compiler (Gcc) Flags That Setup.Py Uses by Default
How to Save Final Model Using Keras
How to Overlay Two Graphs in Seaborn
Representing and Solving a Maze Given an Image
How to Update SQLalchemy Row Entry
Pandas Dataframe Column to List
Matplotlib Custom Marker/Symbol
Pandas Latitude-Longitude to Distance Between Successive Rows
Building a Minimal Plugin Architecture in Python
Is There a Function to Determine Which Quarter of the Year a Date Is In
Regex for Existence of Some Words Whose Order Doesn't Matter