我将在 python3 中找到序列的长度,发现range
现在是<class type>
而不是<type builtin_function_or_method>
这样,range
调用似乎在内存中创建了一个生成器而没有创建list
的开销,并在 python2 中填充它(如果我,请纠正我这是误解,或者我错了。)
我现在的问题是,计算序列长度会有明显的改善吗,我称之为len(range(start, stop, step))
而不是计算int(math.ceil((stop - start) / step))
。
这是我将要做的一个粗略的例子:
s = list(range(limit))
s[1] = 0
for i in range(2, sqrtn + 1):
if s[i]:
s[i*i: limit: i] = [0] * len(range(i*i, limit, i)) # call to range
上述实际上比计算长度更有效吗?
from math import ceil
s = list(range(limit))
s[1] = 0
for i in range(2, sqrtn + 1):
if s[i]:
s[i*i: limit: i] = [0] * int(math.ceil((limit - i*i) / i)) # no range call
答案 0 :(得分:1)
理论上,是的,在实践中,没有。 Windows x64构建CPython 3.5.0的所有时间(特定时间无关紧要;每种方法的相对时间都是重要的):
>>> from math import ceil
>>> start, stop, step = 100*100, 100000, 100
>>> min(timeit.repeat('(stop - start + (step - 1)) // step', 'from __main__ import start, stop, step', number=100000))
0.016031580173375914
>>> min(timeit.repeat('ceil((stop - start) / step)', 'from __main__ import start, stop, step, ceil', number=100000))
0.024184756985505373
>>> min(timeit.repeat('len(range(start, stop, step))', 'from __main__ import start, stop, step', number=100000))
0.03917228338013956
我用几个不同的端点运行这些测试;如果值足够大以至于无法在Py_ssize_t
中完成数学运算,range
和ceil
方法会更加接近(ceil
减慢速度),但纯int
数学方法赢得了我所经历的每一项测试。 range
和ceil
都有问题;对于非常大的数字,range
会抛出OverflowError
(它不能包含比Py_ssize_t
更多的元素)和ceil
(或更确切地说,浮点数)当你超过~53位值时,ceil
之前的除法将产生浮点精度误差。纯int
数学既快又可靠,应该是首选。
也就是说,其他Python解释器(PyPy,IronPython,Jython,Cython)可以使用像range
这样的特殊情况(以及整数数学),并且可以很容易地具有完全不同的性能特征。
这里的实际开销不是len
计算。 range
实际上计算长度并在构建期间将其缓存在内部;检索它与任何命名函数调用一样接近free(并且所有内置序列都是如此;最坏的情况是它们必须从C级int
构造Python级int
,但所有数学运算都做同样的事情)。检索长度的实际成本:
>>> min(timeit.repeat('len(r)', 'from __main__ import start, stop, step; r = range(start, stop, step)', number=100000))
0.0076398965929911355