Python create function in a loop capturing the loop variable
Yep, the usual "scoping problem" (actually a binding-later-than-you want problem, but it's often called by that name). You've already gotten the two best (because simplest) answers -- the "fake default" i=i
solution, and functools.partial
, so I'm only giving the third one of the classic three, the "factory lambda":
for i in range(0,10):
funcs.append((lambda i: lambda x: f(i, x))(i))
Personally I'd go with i=i
if there's no risk of the functions in funcs
being accidentally called with 2 parameters instead of just 1, but the factory function approach is worth considering when you need something a little bit richer than just pre-binding one arg.
lambdas in python are closures.... the arguments you give it aren't going to be evaluated until the lambda is evaluated. At that time, i=9 regardless, because your iteration is finished.
The behavior you're looking for can be achieved with functools.partial
import functools
def f(a,b):
return a*b
funcs = []
for i in range(0,10):
funcs.append(functools.partial(f,i))
All the lambdas end up being bound to the last one. See this question for a longer answer:
How do I create a list of Python lambdas (in a list comprehension/for loop)?
There's only one i
which is bound to each lambda, contrary to what you think. This is a common mistake.
One way to get what you want is:
for i in range(0,10):
funcs.append(lambda x, i=i: f(i, x))
Now you're creating a default parameter i
in each lambda closure and binding to it the current value of the looping variable i
.