代码之家  ›  专栏  ›  技术社区  ›  Elias Strehle

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

  •  0
  • Elias Strehle  · 技术社区  · 7 年前

    我想在列表理解中应用一个对某些值不起作用的函数。 一个简单的例子是 [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 以某种方式使列表理解跳过 元素?

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

    备注2: 与…对比 this question ,我可以在函数中显式地处理异常(例如 试驾 )中。我的问题主要是如何把最后两步结合起来( result_with_none = ... result = ... )合二为一。

    1 回复  |  直到 7 年前
        1
  •  1
  •   FHTMitchell    7 年前

    我认为您的第一个解决方案是明确的,这是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