Rationale
Consider this example:
# choosing a function which has a domain [-1, 1]
func = lambda x: 1 / x
# try to interpolate the coordiates with a dict comprehension
{x: func(x) for x in range(-5, 5)}
# This will generate a "ZeroDivisionError: division by zero"
In this example when x
is 0, a ZeroDivisionError
is raised and interrupts the comprehension.
We can solve this problem by introducing a new syntax in Python:
{x: func(x) for x in range(-5, 5) except ZeroDivisionError}
# Expected output: {-5: -0.2, -4: -0.25, -3: -0.3333333333333333, -2: -0.5, -1: -1.0, 1: 1.0, 2: 0.5, 3: 0.3333333333333333, 4: 0.25}
This seems to be relatively useless since we could easily work around by adding the filter if x != 0
in the comprehension. But if an arbitrary function is chosen without knowing the domain, then error handling is NEEDED instead of HELPFUL:
import numpy as np
import math
func = eval(input()) # here I put math.asin
# There is *absolutely* no way to do LBYL here,
# and we should have syntax like this to do EAFP:
{x: func(x) for x in np.linspace(-2, 2, 10) except ValueError}
# Expected output: {-0.6666666666666667: -0.7297276562269664, -0.22222222222222232: -0.22409309230137095, 0.22222222222222232: 0.22409309230137095, 0.6666666666666665: 0.7297276562269661}
Syntax
- By simply adding
except
orexcept SomeError
means the same ascontinue
, example above has the same meaning as the one showing below:
dest = {}
for x in np.linspace(-2, 2, 10):
try:
a[x] = func(x)
except ValueError:
continue
- Adding an expression after handling the error simply means âwhen the error occurs evaluate this expression and use it as valueâ:
[1 / x for x in range(-5, 5) if not x % 2 except ZeroDivision "oopsie"]
# Expected Output: [-0.25, -0.5, "oopsie", 0.5, 0.25]
For dicts, the default value should always be a tuple, where the first element is used as the key and second element as the value:
{x: 1 / x for x in range(-5, 5) if not x % 2 except ZeroDivision as e (x, e)}
# Expected Output: {-4: -0.25, -2: -0.5, 0: ZeroDivisionError('division by zero'), 2: 0.5, 4: 0.25}
- Multiple exception handling:
The syntax should allow multiple excepts chaining together just like chaining ifs:
def my_func(x):
if x == 0:
raise TypeError
if x == 2:
raise ValueError
return x
[my_func(x) for x in range(-2, 4) except TypeError except ValueError "oopsie"]
# expected output: [-2, -1, 1, "oopsie", 3]
It would be great if we have something like this to embrace EAFP and strengthen comprehensions.