Python 避免在列表中多次调用同一函数
我有一个返回元组的函数,如下所示:Python 避免在列表中多次调用同一函数,python,python-3.x,Python,Python 3.x,我有一个返回元组的函数,如下所示: def foo(i,j): # does stuff return (m,n) 我想对两个输入进行双列表理解,并获得返回元组中两个元素的和的值。我认为最简单的方法是: [foo(i,j)[0]+foo(i,j)[1]代表x中的i代表y中的j] 这种方法的问题是,每对i,j调用两次foo,使得列表理解速度比需要的慢。如何更改列表理解,使每对I,j只调用一次foo?尝试以下操作: [sum(foo(i,j)) for i in x for j i
def foo(i,j):
# does stuff
return (m,n)
我想对两个输入进行双列表理解,并获得返回元组中两个元素的和的值。我认为最简单的方法是:
[foo(i,j)[0]+foo(i,j)[1]代表x中的i代表y中的j]
这种方法的问题是,每对i,j
调用两次foo
,使得列表理解速度比需要的慢。如何更改列表理解,使每对I,j
只调用一次foo
?尝试以下操作:
[sum(foo(i,j)) for i in x for j in y]
尝试Python的内置函数:
[sum(foo(i,j)) for i in x for j in y]
样本运行:
def foo(m,n):
print(f'called: foo({m},{n})')
return m,n
x = [1,2]
y = [3,4]
print('Run without sum() - expect 8 calls')
[foo(i,j)[0] + foo(i,j)[1] for i in x for j in y]
print('\nRun with sum() - expect 4 calls')
[sum(foo(i,j)) for i in x for j in y]
> Run without sum() - expect 8 calls
> called: foo(1,3)
> called: foo(1,3)
> called: foo(1,4)
> called: foo(1,4)
> called: foo(2,3)
> called: foo(2,3)
> called: foo(2,4)
> called: foo(2,4)
> [4, 5, 5, 6]
>
> Run with sum() - expect 4 calls
> called: foo(1,3)
> called: foo(1,4)
> called: foo(2,3)
> called: foo(2,4)
> [4, 5, 5, 6]
您可以使用Python 3.8+
[p[0] + p[1] for i in x for j in y if (p := foo(i,j))]
需要if条件使其成为双for循环的有效用法(单for循环不需要)。但是,如果总是真的,因为foo返回一个元组
更好的版本(由@MisterMiyagi提供)
这是由于需要if条件。操作符模块将所有操作符作为一级函数提供
operator.add(a,b)
相当于a+b
,而operator.add(*ab)
相当于operator.add(ab[0],ab[1])
使用add
比sum
稍快一些:
In [1]: %timeit [add(*foo(i, j)) for i in range(50) for j in range(50)]
409 µs ± 8.27 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [2]: %timeit [sum(foo(i, j)) for i in range(50) for j in range(50)]
554 µs ± 5.97 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [3]: %timeit [add(*foo(i, j)) for i in range(500) for j in range(500)]
47.2 ms ± 215 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [4]: %timeit [sum(foo(i, j)) for i in range(500) for j in range(500)]
61.5 ms ± 215 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
尼斯:-)我不熟悉这个,接受这个答案是因为它是最简单的general@bleutooth65--是的,海象是3.8+的一个很好的特性。不需要有害的
if
条款!改为使用[(p:=foo(i,j)[0]+p[1]表示x中的i表示y中的j]
。@MisterMiyagi--表达式中有错误吗?我使用as is:p:=foo(i,j)]^SyntaxError:无效语法
from operator import add
[add(*foo(i,j)) for i in x for j in y]
In [1]: %timeit [add(*foo(i, j)) for i in range(50) for j in range(50)]
409 µs ± 8.27 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [2]: %timeit [sum(foo(i, j)) for i in range(50) for j in range(50)]
554 µs ± 5.97 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [3]: %timeit [add(*foo(i, j)) for i in range(500) for j in range(500)]
47.2 ms ± 215 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [4]: %timeit [sum(foo(i, j)) for i in range(500) for j in range(500)]
61.5 ms ± 215 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)