Python中的迭代函数

时间:2014-02-28 18:22:19

标签: python

给定函数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]))

但我想知道是否有更好或更快的方法来做到这一点。

2 个答案:

答案 0 :(得分:10)

有几种方法可以优化此代码:

  1. 使用itertools.repeat(None, times)控制循环次数更快(这可以避免在每次迭代时创建新的,未使用的整数对象)。

  2. 您可以通过将其置于函数或生成器中来获得速度(局部变量比全局变量更快。

  3. 您可以通过将中间结果保存在变量中来获得速度,避免[-1]索引查找(LOAD_FAST / STORE_FAST比LOAD_CONST -1和BINARY_SUBSCR更快)。

  4. 您可以使用预先绑定的方法而不是y.append来提高速度。

  5. 例如:

    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 * xx_0 = 2和{{ 1}}。

对于N = 20,Raymond的版本比生成器方法稍快,比功能变体快很多。它似乎取决于lambda x: 2 * x的复杂性,虽然我不知道如何......