我想在列表理解中应用对某些值不起作用的函数。
一个简单的例子是[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 = ...
)合并为一个。
答案 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