跟进: Create List of Single Item Repeated n Times in Python
python -m timeit '[0.5]*100000'
1000 loops, best of 3: 382 usec per loop
python -m timeit '[0.5 for i in range(100000)]'
100 loops, best of 3: 3.07 msec per loop
显然,第二个因为range()而变慢。我不知道为什么[e] * n如此之快(或者它是如何在Python内部实现的)。
答案 0 :(得分:6)
dis.dis让您查看Python在评估每个表达式时执行的操作:
In [57]: dis.dis(lambda: [0.5]*100000)
1 0 LOAD_CONST 1 (0.5)
3 BUILD_LIST 1
6 LOAD_CONST 2 (100000)
9 BINARY_MULTIPLY
10 RETURN_VALUE
In [58]: dis.dis(lambda: [0.5 for i in range(100000)])
1 0 BUILD_LIST 0
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (100000)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 12 (to 28)
16 STORE_FAST 0 (i)
19 LOAD_CONST 2 (0.5)
22 LIST_APPEND 2
25 JUMP_ABSOLUTE 13
>> 28 RETURN_VALUE
列表推导执行循环,每次加载常量0.5
,并将其附加到结果列表。
表达式[0.5]*100000
只需要一个BINARY_MULTIPLY。
另请注意,[obj]*N
会生成一个长度为N
的列表,N
引用完全相同的obj
。
列表推导[expr for i in range(N)]
评估 expr
N
次 - 即使每次expr
评估为相同的值。
答案 1 :(得分:2)
添加到@unutbu所说的内容,BINARY_MULTIPLY
最终会在listobject.c执行此紧密循环:
if (Py_SIZE(a) == 1) {
elem = a->ob_item[0];
for (i = 0; i < n; i++) {
items[i] = elem;
Py_INCREF(elem);
}
return (PyObject *) np;
}
这是非常不言自明的:它在紧密的C循环中对同一个对象进行了大量的引用。因此,几乎100%的[obj] * N
在本机代码中执行,这意味着它真的快。
关于使用可变对象执行此操作的标准警告适用(即:不要使用可变对象),因为您对同一对象进行了大量引用。