From: Alain Ketterlin on
Steven D'Aprano <steve(a)REMOVE-THIS-cybersource.com.au> writes:

>> d = dict()
>> for r in [1,2,3]:
>> d[r] = [r for r in [4,5,6]]
>> print d
>
> This isn't directly relevant to your problem, but why use a list
> comprehension in the first place? [r for r in [4,5,6]] is just [4,5,6],
> only slower.

Sure. But I've actually spent some time reducing the real code to a
simple illustration of the problem.

>> THe problem is that the "r" in d[r] somehow captures the value of the
>> "r" in the list comprehension, and somehow kills the loop interator. The
>> (unexpected) result is {6: [4, 5, 6]}.
>
> Actually, no it doesn't kill the loop at all. You have misinterpreted
> what you have seen:

It kills the iterator, not the loop. Sorry, I used 'kill' with the
meaning it has in compiler textbooks: to assign a new value to a
variable.

> It is expected, because list comprehensions leak the variable into the
> enclosing scope.

Thanks.

-- Alain.
From: Lie Ryan on
On 04/06/10 18:42, Alain Ketterlin wrote:
> Alain Ketterlin <alain(a)dpt-info.u-strasbg.fr> writes:
>
>> d = dict()
>> for r in [1,2,3]:
>> d[r] = [r for r in [4,5,6]]
>> print d
>
> Thanks to Chris and Paul for the details (the list comp. r actually
> leaks). I should have found this by myself.
>
> My background is more on functional programming languages, that's why I
> thought the list comprehension iterator should be purely local. And yes,
> I think a "classical" for-loop iterator should also be local to the
> loop, but I understand this may be too counter-intuitive to many :-)

Actually in other programming languages, loop counter is usually local:

for (int i = 0; i < something; i++) {
....
}
foo(i); // illegal

The reason why python's loop counter leaks is for implementation
simplicity because otherwise python will have to deal with multi-layered
local namespace. Currently in python, the local namespace is just sugar
for an array access (a bit of hand-waving here). In other languages, a
{} block is a namespace and nested {} block means nested namespace even
if they're still in a single function; in python there is only a flat
local namespace and the names resolver becomes a thousand times simpler
(and faster).
From: Stephen Hansen on
On 2010-04-06 09:34:04 -0700, Lie Ryan said:
> in python there is only a flat
> local namespace and the names resolver becomes a thousand times simpler
> (and faster).

This hasn't been true for a long time. Yes, local variables are
optimized to be indexed in an array, but Python has nested scopes for
functions. But it does not have true lexical scoping, no.

--
--S

.... p.s: change the ".invalid" to ".com" in email address to reply privately.

From: Gregory Ewing on
Lie Ryan wrote:
> in python there is only a flat
> local namespace and the names resolver becomes a thousand times simpler

No, it doesn't. The compiler already has to deal with multiple
scopes for nested functions. There may be some simplification,
but not a lot.

The main reason is linguistic. Having nested blocks create new
scopes does not fit well with lack of variable declarations.

--
Greg
From: Rolando Espinoza La Fuente on
On Sun, Apr 4, 2010 at 5:20 PM, Paul Rubin <no.email(a)nospam.invalid> wrote:
[...]
>
>    d[r] = list(r for r in [4,5,6])
>

This have a slightly performance difference. I think mainly the
generator's next() call.

In [1]: %timeit list(r for r in range(10000))
100 loops, best of 3: 2.78 ms per loop

In [2]: %timeit [r for r in range(10000)]
100 loops, best of 3: 1.93 ms per loop

~Rolando