Something is rotten in Denmark...

Jussi Piitulainen jpiitula at ling.helsinki.fi
Tue May 31 06:08:24 EDT 2011


harrismh777 writes:

> >>> fs=[]
> >>> fs = [(lambda n: i + n) for i in range(10)]
> >>> [fs[i](1) for i in range(10)]
> [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]         <=== not good
> 
>      ( that was a big surprise! . . . )
>      ( let's try it another way . . . )

The ten functions share the same i. The list comprehension changes the
value of that i. At the time when the functions are called, the value
is 9.

A different list comprehension mechanism could create a fresh i for
each element instead of changing the value of one i. Then each of the
functions would have a private i which would have the value it had at
the time of the creation of the closure. That is not the Python
mechanism.

The same sharing-an-i thing happens here:

>>> fs = []
>>> for i in range(4):
...    fs.append(lambda n : i + n)
... 
>>> fs[0](0)
3

And the different private-j thing happens here:

>>> gs = []
>>> for i in range(4):
...    gs.append((lambda j : lambda n : j + n)(i))
... 
>>> gs[0](0)
0

You used the lambda itself to introduce its private i in your other
examples, in (lambda n, i=i : i + n). In its i=i, the i to the left is
a different i - will be a fresh i every time the function is called, I
think - while the i to the right gets resolved to the value of the i
that the list comprehension is stepping at the time when the closure
is created.

>       What is going on with the binding in the first
> construct... this seems to reduce the usefulness of lambda to a
> considerable extent?

The lambda is doing its lambda thing exactly. The list comprehension
just updates the one i in whatever you call it that each of the ten
closures remember, and they all observe the updates, so to say.

It's a bit subtle. Using different names might help, like I used j.



More information about the Python-list mailing list