Is `extend` faster than `+=`?
在python中,我们可以用两种方式连接列表:
扩展(另一个步骤)
lst+=另一个
我认为extend比使用+=更快,因为它重用了列表,而不是使用其他两个来创建新的列表。
但当我用timeit测试时,发现+=更快,
1 2 3 4 5 6 7 8
| >>> timeit('l.extend(x)', 'l = range(10); x = range(10)')
0.16929602623
>>> timeit('l += x', 'l = range(10); x = range(10)')
0.15030503273
>>> timeit('l.extend(x)', 'l = range(500); x = range(100)')
0.805264949799
>>> timeit('l += x', 'l = range(500); x = range(100)')
0.750471830368 |
我在timeit中输入的代码有什么问题吗?
- 你能告诉我们你得到的时间吗?此外,这些操作都已就位,因此无法解释任何差异。
- 我认为你应该使用更大的列表,在这么小的范围内,即使是最轻微的后台活动也会破坏结果。
- @我得到的结果与Satoru报告的一致,即使是200+个元素的列表。+=稍快,但始终如一。很奇怪。
- @尼古拉斯:我也测试过,看到了同样的东西。我本以为他们会用另一个来实现一个操作。
- 为什么+=需要创建一个新列表?你把它和+混淆了吗?
- @KennyTM不是说lst = lst + another_lst的捷径吗?
- @Satoru:不,+=可以独立于+过载。
- 可以使用L或'li作为示例列表的名称吗?L看起来像1,有一些字体。
- @Tshepang:你知道你可以在浏览器中配置字体首选项,对吗?
- @沉默,我知道。但删除这种需求是一个很好的实践,尤其是因为我的设置是默认的("允许页面选择自己的字体")。
- 下面是一个解释+=重载如何工作的答案:stackoverflow.com/questions/2347265/…
- @Tshepang:既然你有默认设置,你的评论不应该变成meta中的建议吗?
- @Tz,我们不能为了那些不愿意用li或L代替L的人而改变它的整体外观,对吗?更重要的是,这不仅限于此。其他人会把这个打印出来,两个字符看起来是一样的。我们应该让他们也改变字体吗?顺便说一句,我从一本python的书中得到了这个建议,并认为它是一个有用的指导方针。
- @Tshepang:如果你的单空间字体显示"l"和"1",你的单空间字体就坏了,换一个新的。我的工作很好。
- @尼克,我注意到这里有个误会。我不是说江户十一〔5〕和江户十一〔8〕看起来完全一样。我的意思是它们看起来很像…太相似了。
- 连接两个列表的可能重复-"+="和extend()之间的差异
编辑:我已经测试了性能,无法将差异复制到任何重要级别。
这是字节码——感谢@john machine指出了不一致之处。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| >>> import dis
>>> l = [1,2,3]
>>> m = [4,5,6]
>>> def f1(l, m):
... l.extend(m)
...
>>> def f2(l,m):
... l += m
...
>>> dis.dis(f1)
2 0 LOAD_FAST 0 (l)
3 LOAD_ATTR 0 (extend)
6 LOAD_FAST 1 (m)
9 CALL_FUNCTION 1
12 POP_TOP
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
>>> dis.dis(f2)
2 0 LOAD_FAST 0 (l)
3 LOAD_FAST 1 (m)
6 INPLACE_ADD
7 STORE_FAST 0 (l)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE |
注意,extend使用CALL_FUNCTION而不是INPLACE_ADD。任何细微的性能差异都可以归结为这一点。
- 不仅可以查找属性,还可以调用函数。
- @康斯坦丁,我认为主要是属性查找。INPLACE_ADD只是路由到对象上定义的任何__iadd__方法。
- @卡特里亚克斯,@constantin,@aaronsterling:sheesh.它是一个加载和调用函数,而不是就地添加和存储
- @卡特里亚克斯:更令人困惑的是,你的名单在一个案例中是全球性的,在另一个案例中是本地的。考虑给出具有相同管理费用的最小示例,例如,在这种情况下,def f1(a, b): a.extend(b)和def f2(a, b): a += b。
- @约翰:是的。已编辑,谢谢=0。我也不能在任何程度上复制性能差异。
- @我把它放在我的系统里,和手术室差不多。
- @约翰,你为什么这么强调商店的速度差?似乎它所扮演的角色,如果有什么可以算在+=上的话,对extend来说,甚至都不是必要的。
- 谢谢。这很有趣。
- @aaronsterling:"sheesh"和emphasis,因为你们都没有提到它是所用操作码差异的一部分。当然,这意味着所使用的操作码并不能为任何速度差提供任何明确的解释——存在争议的速度差,没有显示出可靠的基准测试结果。