Why does this code print "d, d, d, d", and not "a, b, c, d"? How can I modify it to print "a, b, c, d"?
cons = []
for i in ['a', 'b', 'c', 'd']:
cons.append(lambda: i)
print ', '.join([fn() for fn in cons])
Why does this code print "d, d, d, d", and not "a, b, c, d"? How can I modify it to print "a, b, c, d"?
cons = []
for i in ['a', 'b', 'c', 'd']:
cons.append(lambda: i)
print ', '.join([fn() for fn in cons])
When you create a closure, the variables that are "closed over" by your lambdas (in this case,
i
) are bound by name, not value. Therefore, whenever you call your lambdas, they'll use the last value of 'i'.'Erics' answer as a comprehension :
Here's the simple fix you need to make that work:
Oddly enough, this is not a variable scope problem, but a quesiton of the semantics of python's
for
loop (and of python's variables).As you expect,
i
inside your lambda correctly refers to the variablei
in the nearest enclosing scope. So far, so good.However, you are expecting this to mean the following happens:
What actually happens is this:
Thus, your code is appending the same variable
i
to the list four times -- and by the time the loop exits,i
has a value of'd'
.Note that if python functions took and returned the value of their arguments / return values by value, you would not notice this, as the contents of
i
would be copied on each call toappend
(or, for that matter, on each return from the anonymous function created withlambda
). In actuality, however, python variables are always references to a particular object-- and thus your four copies ofi
all refer to'd'
by then end of your loop.