lambda in list comprehension acting funny
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Thu Jul 12 07:29:49 EDT 2012
On Thu, 12 Jul 2012 09:44:15 +0000, Alister wrote:
> On Wed, 11 Jul 2012 08:43:11 +0200, Daniel Fetchinson wrote:
>
>>> funcs = [ lambda x: x**i for i in range( 5 ) ]
[...]
> Having read Steve's explanation in the other thread (which I think has
> finally flipped the light switch on lambda for me) it only requires a
> minor change
>
> funcs=[ lambda x,y=i:x**y for i in range(5) ]
>
> although I cant actually think why this construct would be needed in
> practice, how are you actually using it
I would expect that the example given is just sample code demonstrating
the problem. A slightly more realistic case might be something like
defining a bunch of callbacks for, say, a GUI application.
For example, the good ol' calculator app, where you have ten buttons for
digits 0-9. So you might give each button a callback function that
inserts its own digit into the text field:
buttons = [make_button(name=str(i)) for i in range(10)]
That works fine. So now you go to add a callback to each one:
buttons = [make_button(name=str(i), callback=lambda: FIELD.insert(i))
for i in range(10)]
and lo and behold, the ten buttons named "0" through "9" all insert 9.
The reason is that the callback functions aren't given the value of i,
but only the name[1] "i". By the time the callbacks are actually used,
i == 9 and all the buttons share the same value.
[1] Technically closures may not store values by name, but the principle
is sound: the function, when called later, looks up the current value of
variable i, which is not necessarily the same as it was when the closure
was originally defined.
--
Steven
More information about the Python-list
mailing list