This question is distilled from the original application involving callback functions for Tkinter buttons. This is one line that illustrates the behavior.
lam
Use a parameter with default value to bind the current value of i
to a local variable. When the lambda
gets called without an argument, the local variable i
is assigned the default value:
In [110]: lambdas = [lambda i=i: i for i in range(3)]
In [111]: for lam in lambdas:
.....: print(lam())
.....:
0
1
2
When i
is not a local variable, Python looks up its value in the enclosing scope. The value that is found is the last value i
attained in the for-loop of the list comprehension. That is why, without the parameter with default value, each lambda
returns 2 since the for-loop has completed by the time the lambdas get called.
Another common approach to solving this problem is to use a closure -- a function that can refer to environments that are no longer active such as the local namespace of an outer function, even after that function has returned.
def make_func(i):
return lambda: i
lambdas = [make_func(i) for i in range(3)]
for lam in lambdas:
print(lam())
prints
0
1
2
This works because when lam()
gets called, since the i
in the lambda
function's body is not a local variable, Python looks for the value of i
in
the enclosing scope of the function make_func
. Its local namespace is still
accessible to the closure, lam
, even though make_func
has already
completed. The value in that local namespace is the value which was passed to
make_func
, which is, happily, the desired value of i
.
As already mentioned by mkrieger1, another way to create a new function with some argument values already supplied is to use functools.partial:
lambdas = [functools.partial(lambda x: x, i) for i in range(3)]