给定函数f( )
,数字x
和整数N
,我想计算列表:
y = [x, f(x), f(f(x)), ..., f(f... M times...f(f(x)) ]
在Python中执行此操作的一种显而易见的方法是使用以下Python代码:
y = [x]
for i in range(N-1):
y.append(f(y[-1]))
但我想知道是否有更好或更快的方法来做到这一点。
答案 0 :(得分:10)
有几种方法可以优化此代码:
使用itertools.repeat(None, times)
控制循环次数更快(这可以避免在每次迭代时创建新的,未使用的整数对象)。
您可以通过将其置于函数或生成器中来获得速度(局部变量比全局变量更快。
您可以通过将中间结果保存在变量中来获得速度,避免[-1]
索引查找(LOAD_FAST / STORE_FAST比LOAD_CONST -1和BINARY_SUBSCR更快)。
您可以使用预先绑定的方法而不是y.append
来提高速度。
例如:
from itertools import repeat
def nest(func, x, times):
result = [x]
result_append = result.append
for _ in repeat(None, times):
x = func(x)
result_append(x)
return result
以下是一个示例电话:
>>> def double(x):
return 2 * x
>>> nest(double, 3, 5)
[3, 6, 12, 24, 48, 96]
这是显示紧密内循环,使用局部变量和绑定方法的反汇编:
>>> from dis import dis
>>> dis(nest)
2 0 LOAD_FAST 1 (x)
3 BUILD_LIST 1
6 STORE_FAST 3 (result)
3 9 LOAD_FAST 3 (result)
12 LOAD_ATTR 0 (append)
15 STORE_FAST 4 (result_append)
4 18 SETUP_LOOP 45 (to 66)
21 LOAD_GLOBAL 1 (repeat)
24 LOAD_CONST 0 (None)
27 LOAD_FAST 2 (times)
30 CALL_FUNCTION 2
33 GET_ITER
>> 34 FOR_ITER 28 (to 65)
37 STORE_FAST 5 (_)
5 40 LOAD_FAST 0 (func)
43 LOAD_FAST 1 (x)
46 CALL_FUNCTION 1
49 STORE_FAST 1 (x)
6 52 LOAD_FAST 4 (result_append)
55 LOAD_FAST 1 (x)
58 CALL_FUNCTION 1
61 POP_TOP
62 JUMP_ABSOLUTE 34
>> 65 POP_BLOCK
7 >> 66 LOAD_FAST 3 (result)
69 RETURN_VALUE
答案 1 :(得分:6)
您可以使用生成器:
import itertools
def apply_apply(f, x_0):
x = x_0
while True:
yield x
x = f(x)
....
y = list(itertools.islice(apply_apply(f, x), N))
另一种方法是走完全功能路线:
from functools import reduce
y = list(reduce(lambda x, f: x + [f(x[-1])], [[x_0]] + [f] * (N - 1)))
作为旁注,两种解决方案在我的机器上的性能优于公认的解决方案,发电机为2ms,功能为2ms,Raymond的代码为f = lambda x: x * x
,x_0 = 2
和{{ 1}}。
对于N = 20
,Raymond的版本比生成器方法稍快,比功能变体快很多。它似乎取决于lambda x: 2 * x
的复杂性,虽然我不知道如何......