10

所以有两种方法可以获取一个列表并将第二个列表的成员添加到第一个列表中。您可以使用列表连接,也可以对其进行迭代。你可以:

for obj in list2:
    list1.append(obj)

或者您可以:

list1 = list1 + list2

或者

list1 += list2

我的问题是:哪个更快,为什么?我使用两个非常大的列表(超过 10000 个对象)对此进行了测试,似乎迭代方法比列表连接(如 l1 = l1 + l2)快得多。为什么是这样?有人可以解释吗?

4

3 回答 3

15

append一次添加每个项目,这是其缓慢的原因,以及对append.

但是在这种情况下,运算+=不是+. 运算符实际上并没有创建一个新列表然后将其+=分配回去,它修改了左侧的操作数。timeit使用 10,000 次时非常明显。

>>> timeit.timeit(stmt="l = l + j", setup="l=[1,2,3,4]; j = [5,6,7,8]", number=10000)
0.5794978141784668
>>> timeit.timeit(stmt="l += j", setup="l=[1,2,3,4]; j = [5,6,7,8]", number=10000)
0.0013298988342285156

+=更快(大约 500 倍)

你也有extend列表的方法,它可以附加任何可迭代的(不仅仅是另一个列表),比如l.extend(l2)

>>> timeit.timeit(stmt="l.extend(j)", setup="l=[1,2,3,4]; j = [5,6,7,8]", number=10000)
0.0016009807586669922
>>> timeit.timeit(stmt="for e in j: l.append(e)", setup="l=[1,2,3,4]; j = [5,6,7,8]", number=10000)
0.00805807113647461

逻辑上等同于追加,但如您所见,速度要快得多。

所以解释一下:迭代比+ 因为+必须构造一个全新的列表更快

extend比迭代更快,因为它是一个内置的列表方法并且已经过优化。逻辑上等同于重复追加,但实现方式不同。

+=比它更快,extend因为它可以就地修改列表,知道列表必须有多大并且没有重复的函数调用。它假设您将列表附加到另一个列表/元组

于 2013-07-05T00:08:42.337 回答
0

我运行了以下代码

l1 = list(range(0, 100000))
l2 = list(range(0, 100000))

def t1():
    starttime = time.monotonic()
    for item in l1:
        l2.append(item)
    print(time.monotonic() - starttime)

l1 = list(range(0, 100000))
l2 = list(range(0, 100000))

def t2():
    starttime = time.monotonic()
    global l1
    l1 += l2
    print(time.monotonic() - starttime)

并得到了这个,这表明添加列表(+=)更快。

0.016047026962041855

0.0019438499584794044

于 2013-07-05T00:08:14.853 回答
0

你测量错误;多次迭代和调用append比一次调用要慢得多,因为许多函数调用(至少在 cpython 中)的开销使与实际列表操作有关的任何事情都相形见绌,如此处所示,Linux x64 上的 cPython 2.7.5 :

$ python -m timeit -s 'x = range(10000);y = range(10000)' 'for e in y:x.append(e)'
100 loops, best of 3: 2.56 msec per loop
$ python -m timeit -s 'x = range(10000);y = range(10000)' 'x = x + y'
100 loops, best of 3: 8.98 msec per loop
$ python -m timeit -s 'x = range(10000);y = range(10000)' 'x += y'
10000 loops, best of 3: 105 usec per loop
$ python -m timeit -s 'x = range(10000);y = range(10000)' 'x.extend(y)'
10000 loops, best of 3: 107 usec per loop

请注意,这x = x + y会创建列表的第二个副本(至少在 cPython 中)。x.extend(y)和它的表亲x += y做同样的事情append,就像多次调用一样,只是没有实际调用 Python 方法的开销。

于 2013-07-05T00:10:17.410 回答