Message312863
FYI, here is the disassembly of the inner code objects. It shows where the difference in speed arises:
>>> from dis import dis
>>> def f():
lc = [i for i in [1, 2]]
ge = (i for i in [1, 2])
return lc, ge
>>> for obj in f.__code__.co_consts:
if type(obj) == type(f.__code__):
print(obj)
dis(obj)
<code object <listcomp> at 0x113d881e0, file "<pyshell#26>", line 2>
2 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 8 (to 14)
6 STORE_FAST 1 (i)
8 LOAD_FAST 1 (i)
10 LIST_APPEND 2 <-- Append directly
12 JUMP_ABSOLUTE 4
>> 14 RETURN_VALUE
<code object <genexpr> at 0x1035afe40, file "<pyshell#26>", line 3>
3 0 LOAD_FAST 0 (.0)
>> 2 FOR_ITER 10 (to 14)
4 STORE_FAST 1 (i)
6 LOAD_FAST 1 (i)
8 YIELD_VALUE <-- Pass data through iterator
10 POP_TOP <-- Dispose of None from send()
12 JUMP_ABSOLUTE 2
>> 14 LOAD_CONST 0 (None)
16 RETURN_VALUE
The list comprehension builds the list directly with the high-speed specialized, LIST_APPEND opcode.
The generator runs YIELD_VALUE and POP_TOP but the work isn't done. There needs to be a context switch to list_extend() which then extract the value from the iterator and finally appends it to the list.
Executive summary: there is overhead when passing data through the iterator protocol. |
|
Date |
User |
Action |
Args |
2018-02-25 21:28:09 | rhettinger | set | recipients:
+ rhettinger, scoder, steven.daprano, Antony.Lee |
2018-02-25 21:28:09 | rhettinger | set | messageid: <1519594089.84.0.467229070634.issue32945@psf.upfronthosting.co.za> |
2018-02-25 21:28:09 | rhettinger | link | issue32945 messages |
2018-02-25 21:28:09 | rhettinger | create | |
|