我使用timeit
模块对这两个代码段进行了比较,并意识到第二个代码片段稍快一些:
~$ python -m timeit —setup "l=[1, 2];k=1" "l[k==1]"
10000000 loops, best of 3: 0.0414 usec per loop
~$ python -m timeit —setup "l=[1, 2];k=1" "l[0 if k==1 else 1]"
10000000 loops, best of 3: 0.0372 usec per loop
由于逻辑是相同的,我认为评估布尔对象比整数等价(True
== 1和False
== 0)需要更多的时间,因此我提出了以下基准测试事实证明我是对的:
~$ python -m timeit —setup "l=range(1000)" "l[False]"
10000000 loops, best of 3: 0.0411 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[False]"
10000000 loops, best of 3: 0.0394 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[False]"
10000000 loops, best of 3: 0.0416 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[True]"
10000000 loops, best of 3: 0.0428 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[True]"
10000000 loops, best of 3: 0.0394 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[True]"
10000000 loops, best of 3: 0.0393 usec per loop
~$
~$
~$ python -m timeit —setup "l=range(1000)" "l[0]"
10000000 loops, best of 3: 0.0232 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[0]"
10000000 loops, best of 3: 0.0232 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[0]"
10000000 loops, best of 3: 0.0232 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[1]"
10000000 loops, best of 3: 0.0232 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[1]"
10000000 loops, best of 3: 0.0232 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[1]"
10000000 loops, best of 3: 0.0232 usec per loop
但我不知道其根本原因是什么。我的意思是为什么评估True
和False
需要更多时间?在基准测试中我也发现了另一个神秘的事情。在基准测试的第一部分中,结果存在差异,而第二部分的数字是稳定的。
答案 0 :(得分:3)
对于l[k==1]
和l[0 if k==1 else 1]
,您没有足够长的时间。你看到的差异在于你从随机变化中获得的差异。我不确定哪种形式最终更快,但更长的试验显示出相反的效果:
>>> timeit.timeit('l[k==1]', 'l=[1,2];k=1', number=100000000)
10.782931089401245
>>> timeit.timeit('l[0 if k==1 else 1]', 'l=[1,2];k=1', number=100000000)
11.140317916870117
l[0 if k==1 else 1]
出乎意料地具有竞争力,因为l[k==1]
没有达到BINARY_SUBSCR
操作码的fast path:
TARGET_NOARG(BINARY_SUBSCR)
{
w = POP();
v = TOP();
if (PyList_CheckExact(v) && PyInt_CheckExact(w)) {
/* INLINE: list[int] */
Py_ssize_t i = PyInt_AsSsize_t(w);
if (i < 0)
i += PyList_GET_SIZE(v);
if (i >= 0 && i < PyList_GET_SIZE(v)) {
x = PyList_GET_ITEM(v, i);
Py_INCREF(x);
}
else
goto slow_get;
}
else
slow_get:
x = PyObject_GetItem(v, w);
在第二次测试中,还有另一个因素,在Python 2中,True
是内置变量查找,而1
则更快LOAD_CONST
。 LOAD_CONST
仅索引到代码对象的co_consts
元组,而内置查找需要两次dict查找。
答案 1 :(得分:0)
boolean
和integer
师have been asked earlier之间的差异。但是,没有讨论它的(in)稳定性。下面,我的分数:
<强> Python2 强>
~$ python2 -m timeit --setup "l=range(1000)" "l[False]"
10000000 loops, best of 3: 0.0366 usec per loop
~$ python2 -m timeit --setup "l=range(1000)" "l[False]"
10000000 loops, best of 3: 0.0332 usec per loop
~$ python2 -m timeit --setup "l=range(1000)" "l[1]"
10000000 loops, best of 3: 0.0193 usec per loop
~$ python2 -m timeit --setup "l=range(1000)" "l[1]"
100000000 loops, best of 3: 0.0194 usec per loop
~$ python2 -m timeit --setup "l=range(1000)" "l[1]"
100000000 loops, best of 3: 0.0195 usec per loop
~$ python2 -m timeit --setup "l=range(1000)" "l[0]"
100000000 loops, best of 3: 0.0196 usec per loop
Python 3
~$ python -m timeit --setup "l=range(1000)" "l[0]"
10000000 loops, best of 3: 0.0712 usec per loop
~$ python -m timeit --setup "l=range(1000)" "l[0]"
10000000 loops, best of 3: 0.072 usec per loop
~$ python -m timeit --setup "l=range(1000)" "l[0]"
10000000 loops, best of 3: 0.0719 usec per loop
~$ python -m timeit --setup "l=range(1000)" "l[False]"
10000000 loops, best of 3: 0.082 usec per loop
~$ python -m timeit --setup "l=range(1000)" "l[False]"
10000000 loops, best of 3: 0.0821 usec per loop
有趣的是:我的分数不仅改变在之间的Python版本,还改变在 Python版本中。由于cache misses,差异是合乎逻辑的。你得分的有趣之处在于0
和1
的差异很小,你看不到4位小数...(我使用的是虚拟机,所以这可能是使我的系统变得足够慢,以便能够轻松看到差异)