20

这是我使用 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

如您所见,代码实际上是在尽可能地提高效率。

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

4

3 回答 3

25
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')

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

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

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

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

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


编辑

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

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

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

时间几乎相同:

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

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

我要从中删除的一件事是,如果您要迭代一个由所有文字组成的对象,请选择 atuple而不是 a list。如果它不完全由文字组成,那么无论您选择list还是tuple.

于 2013-01-21T19:56:31.787 回答
20

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

42.4969689846
5.45146393776
5.38034892082

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

1.42491698265
0.657584905624

分别用于列表和元组。

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

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 是通过 for 循环和列表理解来实现的,以消除两种循环方式之间的效率差异。)

时间是:

53.8211231232
57.1711571217
19.8829259872
28.5986201763

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

于 2015-12-03T21:51:20.770 回答
0

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

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

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

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

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

>>> 
0:00:00.400000
>>> 
0:00:00.390000
>>> 
0:00:00.381000
于 2013-01-21T19:59:01.700 回答