Python中的可变迭代器?

西尔万·勒鲁

在对我的应用程序进行基准测试时,我注意到在Python中按索引访问数组项的成本相对较高,这for v in lst: v大大快于for i in range(len(lst): lst[i]

from array import array

a_ = array('f', range(1000))

def f1():
    a = a_
    acc = 0
    for v in a:
        acc += v

    return acc

def f2():
    a = a_
    acc = 0
    for i in range(len(a)):
        acc += a[i]

    return acc

from dis import dis
from timeit import timeit
for f in f1,f2:
    dis(f)
    print(timeit(f, number=20000))
    print()

生产:

  9           0 LOAD_GLOBAL              0 (a_)
              3 STORE_FAST               0 (a)

 10           6 LOAD_CONST               1 (0)
              9 STORE_FAST               1 (acc)

 11          12 SETUP_LOOP              24 (to 39)
             15 LOAD_FAST                0 (a)
             18 GET_ITER
        >>   19 FOR_ITER                16 (to 38)
             22 STORE_FAST               2 (v)

 12          25 LOAD_FAST                1 (acc)
             28 LOAD_FAST                2 (v)
             31 INPLACE_ADD
             32 STORE_FAST               1 (acc)
             35 JUMP_ABSOLUTE           19
        >>   38 POP_BLOCK

 14     >>   39 LOAD_FAST                1 (acc)
             42 RETURN_VALUE
0.6036834940023255

 17           0 LOAD_GLOBAL              0 (a_)
              3 STORE_FAST               0 (a)

 18           6 LOAD_CONST               1 (0)
              9 STORE_FAST               1 (acc)

 19          12 SETUP_LOOP              40 (to 55)
             15 LOAD_GLOBAL              1 (range)
             18 LOAD_GLOBAL              2 (len)
             21 LOAD_FAST                0 (a)
             24 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             27 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             30 GET_ITER
        >>   31 FOR_ITER                20 (to 54)
             34 STORE_FAST               2 (i)

 20          37 LOAD_FAST                1 (acc)
             40 LOAD_FAST                0 (a)
             43 LOAD_FAST                2 (i)
             46 BINARY_SUBSCR
             47 INPLACE_ADD
             48 STORE_FAST               1 (acc)
             51 JUMP_ABSOLUTE           31
        >>   54 POP_BLOCK

 22     >>   55 LOAD_FAST                1 (acc)
             58 RETURN_VALUE
1.0093544629999087

LOAD_FAST BINARY_SUBSCR使用索引访问时,循环的核心仅在存在额外的操作码方面有所不同但是,这足以使基于迭代器的解决方案比使用索引访问快40%。

不幸的是,以这种形式,迭代器仅可用于读取输入数组。有没有一种方法可以使用“快速”迭代器来更改数组项的位置,还是我必须坚持“慢速”索引访问?

暗影游侠

对于完整循环,您可以使用enumerate,使用索引访问设置值和使用名称读取的方式使用来分割差值

for i, value in enumerate(mysequence):
    mysequence[i] = do_stuff_with(value)

但是,您不能避免在常规循环结构中进行索引重新分配。Python没有等效于C ++参考语义的方法,其中赋值会更改所引用的值,而不是重新绑定名称。

也就是说,如果工作足够简单,那么list理解就可以通过建立新的list和批发的来取代旧的索引而避免使用索引

mysequence[:] = [do_stuff_with(value) for value in mysequence]

分配给完整的片mysequence确保可以对其进行适当的修改,因此对其的其他引用也可以看到更改。[:]如果您不希望出现这种情况可以忽略该行为(您将重新绑定到list没有其他引用的新行为)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章