Python - 附加 VS 扩展效率

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14446128/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:31:55  来源:igfitidea点击:

Python - append VS extend efficiency

pythonlistperformance

提问by Infinity

Here is some code that I wrote using Python:

这是我使用 Python 编写的一些代码:

from math import sqrt
abundant_list = []

for i in range(12,28123+1):
    dividor_list = [1]
    for j in range(2, int(sqrt(i))+1):
        if i%j == 0:
            dividor_list.extend([i/j,j])
    if sum(dividor_list) > i:
        abundant_list.append(i)

print abundant_list

As you can see, the code is really trying to be efficient as much as possible.

正如您所看到的,代码确实尽可能地提高效率。

There is any difference if I use list.appendtwice, or list.extendjust once? I know it can be minor differences, but I would really like to know that :)

如果我使用list.append两次,或list.extend只使用一次,有什么区别吗?我知道这可能是细微的差别,但我真的很想知道:)

采纳答案by mgilson

import timeit

def append2x(foo):
    foo.append(1)
    foo.append(1)

def extend_lst(foo):
    foo.extend([1,1])

def extend_tup(foo):
    foo.extend((1,1))


l1 = []
l2 = []
l3 = []

print timeit.timeit('append2x(l1)',setup = 'from __main__ import append2x,l1')
print timeit.timeit('extend_lst(l2)',setup = 'from __main__ import extend_lst,l2')
print timeit.timeit('extend_tup(l3)',setup = 'from __main__ import extend_tup,l3')

Here's a simple benchmark. My results (os-X, 10.5.8, core2duo, FWIW):

这是一个简单的基准测试。我的结果(os-X、10.5.8、core2duo、FWIW):

0.520906925201  #append
0.602569103241  #extend-list
0.357008934021  #extend-tuple

And the same ordering of the results my linux box (Ubuntu, x86-64 core i7):

我的 linux box(Ubuntu,x86-64 core i7)的结果顺序相同:

0.307395935059  #append
0.319436073303  #extend-list
0.238317012787  #extend-tuple

To me, this says that extendis quicker than append, but that creating a listis relatively expensive compared to creating a tuple

对我来说,这表示extend比 更快append,但是与创建 alist相比,创建 a 相对昂贵tuple



EDIT

编辑

Pointed out in the comments below, because of the immutability of tuples, the interpreter can optimize the creation of the tuple out (it creates the tuple once and re-uses it over and over). If we change the code to:

在下面的评论中指出,由于元组的不变性,解释器可以优化元组的创建(它创建一次元组并一遍又一遍地重用它)。如果我们把代码改成:

def extend_lst(foo):  
    v = 1
    foo.extend([v,v]) 

def extend_tup(foo):
    v = 1
    foo.extend((v,v))

The timings are virtually identical:

时间几乎相同:

0.297003984451  #append
0.344678163528  #extend-list
0.292304992676  #extend-tuple

Although tuplestill consistently beats the list version and barely edges out the appendversion for all of the trials I have done.

尽管tuple仍然始终优于列表版本,并且append在我所做的所有试验中几乎没有超过版本。

One thing that I'm taking away from this is that if you're iterating over an object that consists of all literals, choose a tupleover a list. If it doesn't consist entirely of literals, then it really doesn't matter whether you choose listor tuple.

我要从中带走的一件事是,如果您要迭代由所有文字组成的对象,请选择 a 而tuple不是 a list。如果它不完全由文字组成,那么选择listtuple.

回答by ATOzTOA

They take exact same time.

他们需要完全相同的时间。

Here is the time taken for your code:

这是您的代码所花费的时间:

With dividor_list.extend([i/j,j])

dividor_list.extend([i/j,j])

>>> 
0:00:00.410000
>>> 
0:00:00.383000
>>> 
0:00:00.389000

With dividor_list.append(i/j); dividor_list.append(j)

dividor_list.append(i/j); dividor_list.append(j)

>>> 
0:00:00.400000
>>> 
0:00:00.390000
>>> 
0:00:00.381000

回答by Marc Schulder

It is also worth pointing out that the answer to this question hinges on the small size of the list/tuple that is added on each iteration. For larger lists, extend is clearly superior (and lists vs tuples does not make a difference). Starting with mgilson's answer, I checked behaviour for collections with 600 items, rather than 2: Calling append 600 times takes 8 times as long as using extend()with a manually defined list/tuple (i.e. [v,v,v,v,v,v,v...]):

还值得指出的是,这个问题的答案取决于每次迭代添加的列表/元组的小尺寸。对于较大的列表,extend 显然更胜一筹(并且列表与元组没有区别)。从mgilson回答开始,我检查了具有 600 个项目的集合的行为,而不是 2 个:调用 append 600 次需要 8 倍于使用extend()手动定义的列表/元组(即[v,v,v,v,v,v,v...]):

42.4969689846
5.45146393776
5.38034892082

The bulk of these five seconds is actually the list/tuple creation. Preparing it before the timeitcall brings times for extend down to

这五秒钟的大部分时间实际上是列表/元组的创建。在timeit通话之前准备好将时间延长至

1.42491698265
0.657584905624

for list and tuple, respectively.

分别用于列表和元组。

For a more realistic (and fairer) case, one can dynamically generate the data within the function call:

对于更现实(更公平)的情况,可以在函数调用中动态生成数据:

import timeit

def append_loop(foo, reps):
    for i in range(reps):
        foo.append(i)

def append_comp(foo, reps):
    [foo.append(i) for i in range(reps)]

def extend_lst(foo, reps):
    foo.extend([i for i in range(reps)])

def extend_tup(foo, reps):
    foo.extend((i for i in range(reps)))

repetitions = 600

print timeit.timeit('append_loop([], repetitions)', setup='from __main__ import append_loop, repetitions')
print timeit.timeit('append_comp([], repetitions)', setup='from __main__ import append_comp, repetitions')
print timeit.timeit('extend_lst([], repetitions)', setup='from __main__ import extend_lst, repetitions')
print timeit.timeit('extend_tup([], repetitions)', setup='from __main__ import extend_tup, repetitions')

(Append is implemented both via for-loop and list comprehension to factor out efficiency differences between the two ways of looping.)

(Append 是通过 for-loop 和 list comprehension 实现的,以消除两种循环方式之间的效率差异。)

Timings are:

时间是:

53.8211231232
57.1711571217
19.8829259872
28.5986201763

As we can see, extend with list comprehension is still over two times faster than appending. Also, tuple comprehension appears noticeably slower than list comprehension, and append_componly introduces unnecessary list creation overhead.

正如我们所看到的,使用列表理解扩展仍然比附加快两倍多。此外,元组理解明显比列表理解慢,并且append_comp只会引入不必要的列表创建开销。