修改for循环中的列表元素

时间:2012-02-16 01:36:31

标签: python

我有一个列表a,我希望根据函数a[i: j]更改元素f。我能比天真的方式做得更好吗?

for index in range(i, j):
    a[index] = f(a)

[更好的是指更接近map(f, a)的东西,或更快的东西。]

3 个答案:

答案 0 :(得分:3)

您可以指定切片:

a[i:j] = map(f, a[i:j])

答案 1 :(得分:2)

我不打算做计时练习,但我会告诉你各种选项变成的内部代码。您的代码是naive。切片为l值的基于地图的解决方案为map_lvalue_slice。切片为l值的列表理解为list_comp_lvalue_slice。与列表推导相关的解决方案使用元组,称为tuple_lvalue_slice

>>> from dis import dis
>>> 
>>> def naive(a, f, i, j):
...     for index, ai in enumerate(a[i:j], start=i):
...         a[index] = f(ai)
... 
>>> def map_lvalue_slice(a, f, i, j):
...     a[i:j] = map(f, a[i:j])
... 
>>> def list_comp_lvalue_slice(a, f, i, j):
...     a[i:j] = [f(ai) for ai in a[i:j]]
... 
>>> def tuple_lvalue_slice(a, f, i, j):
...     a[i:j] = tuple(f(ai) for ai in a[i:j])
... 
>>> dis(naive)
  2           0 SETUP_LOOP              55 (to 58)
              3 LOAD_GLOBAL              0 (enumerate)
              6 LOAD_FAST                0 (a)
              9 LOAD_FAST                2 (i)
             12 LOAD_FAST                3 (j)
             15 SLICE+3             
             16 LOAD_CONST               1 ('start')
             19 LOAD_FAST                2 (i)
             22 CALL_FUNCTION          257
             25 GET_ITER            
        >>   26 FOR_ITER                28 (to 57)
             29 UNPACK_SEQUENCE          2
             32 STORE_FAST               4 (index)
             35 STORE_FAST               5 (ai)

  3          38 LOAD_FAST                1 (f)
             41 LOAD_FAST                5 (ai)
             44 CALL_FUNCTION            1
             47 LOAD_FAST                0 (a)
             50 LOAD_FAST                4 (index)
             53 STORE_SUBSCR        
             54 JUMP_ABSOLUTE           26
        >>   57 POP_BLOCK           
        >>   58 LOAD_CONST               0 (None)
             61 RETURN_VALUE        
>>> 
>>> dis(map_lvalue_slice)
  2           0 LOAD_GLOBAL              0 (map)
              3 LOAD_FAST                1 (f)
              6 LOAD_FAST                0 (a)
              9 LOAD_FAST                2 (i)
             12 LOAD_FAST                3 (j)
             15 SLICE+3             
             16 CALL_FUNCTION            2
             19 LOAD_FAST                0 (a)
             22 LOAD_FAST                2 (i)
             25 LOAD_FAST                3 (j)
             28 STORE_SLICE+3       
             29 LOAD_CONST               0 (None)
             32 RETURN_VALUE        
>>> 
>>> dis(list_comp_lvalue_slice)
  2           0 BUILD_LIST               0
              3 LOAD_FAST                0 (a)
              6 LOAD_FAST                2 (i)
              9 LOAD_FAST                3 (j)
             12 SLICE+3             
             13 GET_ITER            
        >>   14 FOR_ITER                18 (to 35)
             17 STORE_FAST               4 (ai)
             20 LOAD_FAST                1 (f)
             23 LOAD_FAST                4 (ai)
             26 CALL_FUNCTION            1
             29 LIST_APPEND              2
             32 JUMP_ABSOLUTE           14
        >>   35 LOAD_FAST                0 (a)
             38 LOAD_FAST                2 (i)
             41 LOAD_FAST                3 (j)
             44 STORE_SLICE+3       
             45 LOAD_CONST               0 (None)
             48 RETURN_VALUE        
>>> 
>>> dis(tuple_lvalue_slice)
  2           0 LOAD_GLOBAL              0 (tuple)
              3 LOAD_CLOSURE             0 (f)
              6 BUILD_TUPLE              1
              9 LOAD_CONST               1 (<code object <genexpr> at 0xb748dc38, file "<stdin>", line 2>)
             12 MAKE_CLOSURE             0
             15 LOAD_FAST                0 (a)
             18 LOAD_FAST                2 (i)
             21 LOAD_FAST                3 (j)
             24 SLICE+3             
             25 GET_ITER            
             26 CALL_FUNCTION            1
             29 CALL_FUNCTION            1
             32 LOAD_FAST                0 (a)
             35 LOAD_FAST                2 (i)
             38 LOAD_FAST                3 (j)
             41 STORE_SLICE+3       
             42 LOAD_CONST               0 (None)
             45 RETURN_VALUE        

在我看来,解决最快解决C代码的解决方案,最好是紧密循环,因为它们可能主要使用优化的C代码而不是主要解释指令。我更喜欢切片作为代码的l值解决方案,我可能倾向于地图解决方案,即使我主要是列表理解人。

此外,这里证明它们是等效的代码:

>>> i, j = 4, 8
>>> def f(ai):
...     return -ai
... 
>>> for fn in (naive, map_lvalue_slice, list_comp_lvalue_slice, tuple_lvalue_slice):
...     a = range(10)
...     fn(a, f, i, j)
...     print "%-40s: %r" % (fn.__name__, a)
... 
naive                                   : [0, 1, 2, 3, -4, -5, -6, -7, 8, 9]
map_lvalue_slice                        : [0, 1, 2, 3, -4, -5, -6, -7, 8, 9]
list_comp_lvalue_slice                  : [0, 1, 2, 3, -4, -5, -6, -7, 8, 9]
tuple_lvalue_slice                      : [0, 1, 2, 3, -4, -5, -6, -7, 8, 9]

答案 2 :(得分:1)

使用列表理解......

a[i:j] = [f(ai) for ai in a[i:j]]

map等价物......

a[i:j] = map(f, a[i:j])