Lambdas inside list comprehensions

The lambda returns the value of i at the time you call it. Since you call the lambda after the loop has finished running, the value of i will always be 9.

You can create a local i variable in the lambda to hold the value at the time the lambda was defined:

>>> [j() for j in [lambda i=i:i for i in range(10)]]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Another solution is to create a function that returns the lambda:

def create_lambda(i):
    return lambda:i
>>> [j() for j in [create_lambda(i) for i in range(10)]]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

This works because there is a different closure (holding a different value of i) created for each invocation of create_lambda.


What you're seeing here is the effect of closures. The lambda is capturing state from the program to be used later. So while each lambda is a unique object, the state isn't necessarily unique.

The actual 'gotchya' here, is that the variable i is captured, not the value that i represents at that point in time. We can illustrate this with a much easier example:

>>> y = 3
>>> f = lambda: y
>>> f()
3
>>> y = 4
>>> f()
4

The lambda holds on to the reference to the variable, and evaluates that variable when you execute the lambda.

To work around this, you can assign to a local variable within the lambda:

>>> f = lambda y=y:y
>>> f()
4
>>> y = 6
>>> f()
4

Finally, in the case of a loop, the loop variable is only 'declared' once. Therefore, any references to the loop variable within the loop will persist past the next iteration. This includes the variable in list comprehensions.