The important thing to be understood here is, the functions are created during the evaluation of the list comprehension, but the value of i
will be evaluated only during the execution of the functions.
So, in your case, you have created three functions and all of them refer i
. When those functions are invoked at runtime, i
will have the value 2
, because that was the last value bound to i
in the last iteration of the for
loop.
Instead, you need to preserve the current value of i
in each of the functions created. So, the common practice is to include a default parameter, like this
>>> lambdas = [lambda i=i: i for i in range(3)]
>>> lambdas[0]()
0
>>> lambdas[1]()
1
>>> lambdas[2]()
2
Now, lambda i=i: i
, creates a default parameter i
which will have the current value of the loop variable i
. So, when the functions are executed, the i
referred is actually the parameter passed to the function, not the loop variable.
To avoid confusion, you can choose to use a different name for the variable, like this
>>> lambdas = [lambda t=i: t for i in range(3)]
If you are looking other ways to avoid this, you can use map
function to apply the numbers to another function which will generate new functions with the current value, like this
>>> lambdas = map(lambda x: lambda: x, range(3))
>>> lambdas[0]()
0
>>> lambdas[1]()
1
>>> lambdas[2]()
2
Here, lambda x: lambda: x
creates an anonymous function which accepts a single parameter x
, and returns another function which doesn't accept any parameters but returns the value x
.
Note: Don't use this map
form in actual code. It might reduce the readability of the code.