提问人:Yam Mesicka 提问时间:1/22/2013 最后编辑:Yam Mesicka 更新时间:11/17/2023 访问量:56163
Python - 附加 VS 扩展效率
Python - append VS extend efficiency
问:
以下是我使用 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
答:
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
list
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
我从中得出的结论是,如果你要遍历一个由所有文字组成的对象,请选择 a 而不是 .如果它不完全由文字组成,那么无论你选择还是 .tuple
list
list
tuple
评论
tuple
它们需要完全相同的时间。
以下是代码所花费的时间:
跟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
评论
timeit
timeit
;-)
dividor_list.extend((i/j,j))
LOAD_CONST
LOAD_FAST
BUILD_LIST
;-)
编辑:正如其他人在评论中指出的那样,Python 中没有元组推导,因为该语法已用于生成器表达式。我已经澄清了描述。
还值得指出的是,这个问题的答案取决于每次迭代中添加的列表/元组的大小。对于较大的列表,extend 显然更胜一筹(列表与元组没有区别)。从 mgilson 的回答开始,我检查了包含 600 个项目而不是 2 个项目的集合的行为:
调用 append 600 次所需的时间是使用手动定义的列表/元组的 8 倍(即):extend()
[v,v,v,v,v,v,v...]
42.4969689846
5.45146393776
5.38034892082
这五秒钟的大部分实际上是列表/元组的创建。在通话前做好准备,可以缩短时间到timeit
1.42491698265
0.657584905624
分别用于 list 和 tuple。
对于更真实(和更公平)的情况,可以在函数调用中动态生成数据:
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_genexp(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_genexp([], repetitions)', setup='from __main__ import extend_genexp, repetitions')
(Append 通过 for 循环和列表推导实现,以分解两种循环方式之间的效率差异。
时间安排如下:
53.8211231232
57.1711571217
19.8829259872
28.5986201763
正如我们所看到的,使用列表推导进行扩展仍然比追加快两倍以上。生成器表达式的显示速度明显慢于列表推导。 只会引入不必要的列表创建开销。append_comp
评论
extend_tup
(i for i in range(reps))
只是另一个基准
这次是在 iPython 中。如果您懒得创建新的 python 脚本,可能会很有用。
In [12]: %%time
...: l = []
...: for ii in range(10000):
...: l += [ii]
...:
CPU times: user 886 µs, sys: 0 ns, total: 886 µs
Wall time: 889 µs
In [13]: %%time
...: l = []
...: for ii in range(10000):
...: l.append(ii)
...:
CPU times: user 669 µs, sys: 92 µs, total: 761 µs
Wall time: 763 µs
下一个:如何向后遍历 STL 列表?
评论
extend
.appends
itertools.product
来获得将因子组合成除数的所有方法,并最终将它们相加。sqrt(28123)
i