mej*_*iwa 7 python list-comprehension
假设我有一个函数func(i)为一个整数i创建一个对象,N是一个非负整数.那么创建等于此列表的列表(不是范围)的最快方法是什么
mylist = [func(i) for i in range(N)]
Run Code Online (Sandbox Code Playgroud)
不采用像在C中创建函数的高级方法?我对上面列表理解的主要关注是,我不确定python是否事先知道预分配mylist的范围(N)的长度,因此必须逐步重新分配列表.是这样的情况还是python足够聪明,首先将mylist分配给长度N然后计算它的元素?如果没有,创建mylist的最佳方法是什么?也许这个?
mylist = [None]*N
for i in range(N): mylist[i] = func(i)
Run Code Online (Sandbox Code Playgroud)
重新编辑:从以前的编辑中删除了误导性信息.
有人写道:"""Python足够聪明.只要您迭代的对象有一个__len__
或一个__length_hint__
方法,Python就会调用它来确定大小并预先分配数组."""
据我所知,列表理解中没有预分配.Python无法从INPUT的大小告知OUTPUT的大小.
看看这个Python 2.6代码:
>>> def foo(func, iterable):
... return [func(i) for i in iterable]
...
>>> import dis; dis.dis(foo)
2 0 BUILD_LIST 0 #### build empty list
3 DUP_TOP
4 STORE_FAST 2 (_[1])
7 LOAD_FAST 1 (iterable)
10 GET_ITER
>> 11 FOR_ITER 19 (to 33)
14 STORE_FAST 3 (i)
17 LOAD_FAST 2 (_[1])
20 LOAD_FAST 0 (func)
23 LOAD_FAST 3 (i)
26 CALL_FUNCTION 1
29 LIST_APPEND #### stack[-2].append(stack[-1]); pop()
30 JUMP_ABSOLUTE 11
>> 33 DELETE_FAST 2 (_[1])
36 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
它只是构建一个空列表,并附加迭代提供的任何内容.
现在看看这个代码,它在列表理解中有一个'if':
>>> def bar(func, iterable):
... return [func(i) for i in iterable if i]
...
>>> import dis; dis.dis(bar)
2 0 BUILD_LIST 0
3 DUP_TOP
4 STORE_FAST 2 (_[1])
7 LOAD_FAST 1 (iterable)
10 GET_ITER
>> 11 FOR_ITER 30 (to 44)
14 STORE_FAST 3 (i)
17 LOAD_FAST 3 (i)
20 JUMP_IF_FALSE 17 (to 40)
23 POP_TOP
24 LOAD_FAST 2 (_[1])
27 LOAD_FAST 0 (func)
30 LOAD_FAST 3 (i)
33 CALL_FUNCTION 1
36 LIST_APPEND
37 JUMP_ABSOLUTE 11
>> 40 POP_TOP
41 JUMP_ABSOLUTE 11
>> 44 DELETE_FAST 2 (_[1])
47 RETURN_VALUE
>>>
Run Code Online (Sandbox Code Playgroud)
相同的代码,加上一些代码来避免LIST_APPEND.
在Python 3.X中,你需要深入挖掘一下:
>>> import dis
>>> def comprehension(f, iterable): return [f(i) for i in iterable]
...
>>> dis.dis(comprehension)
1 0 LOAD_CLOSURE 0 (f)
3 BUILD_TUPLE 1
6 LOAD_CONST 1 (<code object <listcomp> at 0x00C4B8D
8, file "<stdin>", line 1>)
9 MAKE_CLOSURE 0
12 LOAD_FAST 1 (iterable)
15 GET_ITER
16 CALL_FUNCTION 1
19 RETURN_VALUE
>>> dis.dis(comprehension.__code__.co_consts[1])
1 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 18 (to 27)
9 STORE_FAST 1 (i)
12 LOAD_DEREF 0 (f)
15 LOAD_FAST 1 (i)
18 CALL_FUNCTION 1
21 LIST_APPEND 2
24 JUMP_ABSOLUTE 6
>> 27 RETURN_VALUE
>>>
Run Code Online (Sandbox Code Playgroud)
它是相同的旧schtick:从构建一个空列表开始,然后迭代迭代,根据需要附加到列表.我在这里看不到预先分配.
您正在考虑的优化在单个操作码中使用,例如,list.extend(iterable)
如果iterable
可以准确报告其长度,则可以预分配.list.append(object)
给出一个对象,而不是可迭代的对象.
归档时间: |
|
查看次数: |
1442 次 |
最近记录: |