为什么这种复制列表的方法比其他方法快得多?

时间:2017-06-29 15:06:54

标签: python performance list copy

我已经运行了这个列表复制实验,并发现其中一个时间比其他时间快得多,据我所知它复制列表,除非有人能解释其他情况?

import time

def test(d):
    s = time.time()
    for i in range(20000000):
        d['b'] = d['a'].copy()
    e = time.time()
    print (".copy(): "+str(e-s))

    s = time.time()
    for i in range(20000000):
        d['b'][:] = d['a']
    e = time.time()
    print ("[:] on left: "+str(e-s))

    s = time.time()
    for i in range(20000000):
        d['b'] = d['a'][:]
    e = time.time()
    print ("[:] on right: "+str(e-s))

d = {'a': [1,2,3,4],
     'b': []}
test(d)

结果:

.copy(): 4.150316476821899
[:] on left: 2.535377025604248
[:] on right: 4.140159606933594

要证明左边的[:]是复制吗?

d['b'][:] = d['a']
del d['a'][1]
d['a'][0] = "testing"
print (d)

打印:

{'a': ['testing', 3, 4], 'b': [1, 2, 3, 4]}

有人能解释一下这里发生了什么吗?

2 个答案:

答案 0 :(得分:4)

通过在作业中使用[:],您已将左侧列表展开为与右侧列表具有相同数量的元素。其余的测试然后重新使用那些额外的元素; d['b']不再是空的!

换句话说,对于除第一次迭代之外的所有内容,该复制操作不必为列表分配更多索引。这使它更快。

每次都需要在左侧测试列表。使用timeit module进行正确的时间试验。使用适当的大输入:

>>> timeit('a = []; a[:] = b', 'from __main__ import testlist as b')
2.430507270000817
>>> timeit('a = b[:]', 'from __main__ import testlist as b')
2.5209442199993646
>>> timeit('a = b.copy()', 'from __main__ import testlist as b')
2.5766620540016447

分配更多空间实际上并不需要花费那么多时间;你只能看到小清单的效果:

>>> timeit('a[:] = b', 'a = [1, 2, 3, 4]; b = a[:]', number=10000000)
0.7304684859991539
>>> timeit('a = []; a[:] = b', 'a = [1, 2, 3, 4]; b = a[:]', number=10000000)
0.9908717719954439

(注意,这里的迭代次数已从100万增加到1000万)。

对于大型名单,差异大多没有实际意义:

>>> timeit('a[:] = b', 'from __main__ import testlist as b; a = b[:]')
2.4996446009972715
>>> timeit('a = []; a[:] = b', 'from __main__ import testlist as b')
2.4407932980029727

在这个特定的测试运行中,以空列表开头实际上稍快一些;差别主要是噪音,但是重新运行这两项测试会定期交换时间。

答案 1 :(得分:1)

d['b'][:] = d['a']不需要为列表d['b']分配内存,因为它已由前一个操作分配,并且正在重用现有列表对象。其他人创建了一个新列表。