为什么_的范围(n)慢于_""] * n?

时间:2015-05-22 14:57:56

标签: python python-internals

测试for _ in range(n)的替代方案(执行某些操作n次,即使操作不依赖于n的值)我注意到这种模式还有另一种表述更快,for _ in [""] * n

例如:

timeit('for _ in range(10^1000): pass', number=1000000)

返回16.4秒;

而,

timeit('for _ in [""]*(10^1000): pass', number=1000000)

需要10.7秒。

为什么[""] * 10^1000比Python 3中的range(10^1000)快得多?

使用Python 3.3完成所有测试

2 个答案:

答案 0 :(得分:10)

您的问题是您输入错误timeit

您需要提供包含Python语句的timeit个字符串。如果你这样做

stmt = 'for _ in ['']*100: pass'

查看stmt的值。方括号内的引号字符与字符串分隔符匹配,因此它们被Python解释为字符串分隔符。由于Python连接相邻的字符串文字,您将看到您真正拥有的内容与'for _ in [' + ']*100: pass'相同,后者为您提供'for _ in []*100: pass'

所以你的超快速"循环只是循环遍历空列表,而不是100个元素的列表。例如,尝试使用

进行测试
stmt = 'for _ in [""]*100: pass'

答案 1 :(得分:10)

当迭代range()时,会产生0到n之间所有整数的对象;即使使用small integers having been cached,这也需要一小段时间。

另一方面,[None] * n上的循环会生成{1}}对1个对象的引用,并且创建该列表的速度会快一些。

但是,n对象使用更少的内存,更易于启动,这就是人们更喜欢使用它的原因。大多数代码都不必挤出性能的最后一滴。

如果您需要具有该速度,则可以使用不带内存的自定义迭代,使用带有第二个参数的itertools.repeat()

range()

至于你的时间测试,这些问题存在一些问题。

首先,您在from itertools import repeat for _ in repeat(None, n): 时序循环中出错了;你没有嵌入两个引号,你连接了两个字符串并产生了一个空列表

['']*n

当你迭代0次时,它在迭代中将是无与伦比的。

你也没有使用大数字; >>> '['']*n' '[]*n' >>> []*100 [] 是二进制XOR运算符,而不是幂运算符:

^

这意味着您的测试错过了创建空值列表所需的时间。

使用更好的数字和>>> 10^1000 994 可以获得:

None