Terry Reedy wrote:
> Peter Otten wrote:
>
>> List comprehensions delete the helper variable after completion:
>
> I do not believe they did in 2.4. Not sure of 2.5.
As Mario said, 2.4, 2.5, and 2.6 all show the same behaviour.
> There is certainly
> a very different implementation in 3.0 and, I think, 2.6. OP
> neglected to mention Python version he tested on. Code meant to run on
> 2.4 to 3.0 cannot depend on subtle listcomp details.
3.0 behaves different. Like generator expressions listcomps no longer leak
the loop variable, and this is implemented by having each listcomp execute
as a nested function:
> In 3.0
> >>> def f(): [i for i in [1]]
>
> >>> import dis
> >>> dis.dis(f)
> 1 0 LOAD_CONST 1 (<code object <listcomp> at
> 0x01349BF0, file "<pyshell#12>", line 1>)
> 3 MAKE_FUNCTION 0
> 6 LOAD_CONST 2 (1)
> 9 BUILD_LIST 1
> 12 GET_ITER
> 13 CALL_FUNCTION 1
> 16 POP_TOP
> 17 LOAD_CONST 0 (None)
> 20 RETURN_VALUE
This is more robust (at least I can't think of a way to break it like the
2.x approach) but probably slower due to the function call overhead. The
helper variable is still there, but the possibility of a clash with another
helper is gone (disclaimer: I didn't check this in the Python source) so
instead of
# 2.5 and 2.6 (2.4 has the names in a different order)
>>> def f():
... [[i for i in ()] for k in ()]
...
>>> f.func_code.co_varnames
('_[1]', 'k', '_[2]', 'i')
we get
# 3.0
>>> def f():
... [[i for i in ()] for k in ()]
...
>>> f.__code__.co_varnames
()
The variables are gone from f's scope, as 3.x listcomps no longer leak their
loop variables.
>>> f.__code__.co_consts
(None, <code object <listcomp> at 0x2b8d7f6d7530, file "<stdin>", line 2>,
())
>>> outer = f.__code__.co_consts[1]
>>> outer.co_varnames
('.0', '_[1]', 'k')
Again the inner listcomp is separated from the outer.
>>> outer.co_consts
(<code object <listcomp> at 0x2b8d7f6d26b0, file "<stdin>", line 2>, ())
>>> inner = outer.co_consts[0]
>>> inner.co_varnames
('.0', '_[1]', 'i')
Peter
--
http://mail.python.org/mailman/listinfo/python-list