Python列表理解:跳过引发异常的元素

时间:2018-07-19 08:44:48

标签: python exception-handling list-comprehension

我想在列表理解中应用对某些值不起作用的函数。 一个简单的例子是[1/x for x in [-2, -1, 0, 1, 2]]。 我想写一些跳过0并返回以下列表的内容:[-0.5, -1.0, 1.0, 0.5]

到目前为止,我最好的选择是将部门划分为try语句:

def try_div(x):
    try:
        return 1/x
    except ZeroDivisionError:
        pass

result_with_none = [try_div(x) for x in [-2, -1, 0, 1, 2]]
result = [x for x in result_with_none if x is not None]

这似乎有点不便。我可以用一种使列表理解跳过try_div元素的方式重写0吗?

备注:在这个简单的示例中,我当然可以写[try_div for x in [-2, -1, 0, 1, 2] if x != 0]。在我的实际用例中,这是不切实际的,因为先验检查哪些值会引发异常并不容易。

注释2:this question相比,我可以明确地处理函数中的异常(例如try_div)。我的问题主要是关于如何将最后两个步骤(result_with_none = ...result = ...)合并为一个。

1 个答案:

答案 0 :(得分:1)

我认为您的第一个解决方案很明确,这是python中最重要的事情。另外,生成器而不是理解力如何?

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]))

您甚至可以对此进行概括

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