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,因为你们都没有提到它是所用操作码差异的一部分。当然,这意味着所使用的操作码并不能为任何速度差提供任何明确的解释——存在争议的速度差,没有显示出可靠的基准测试结果。