Why does this attempt at creating a list of curried functions not work?
def p(x, num):
print x, num
def test():
a = []
for i in range(10):
In Python, variables created in loops and branches aren't scoped. All of the functions you're creating with lambda
have a reference to the same i
variable, which is set to 9
on the last iteration of the loop.
The solution is to create a function which returns a function, thus scoping the iterator variable. This is why the functools.partial()
approach works. For example:
def test():
def makefunc(i):
return lambda x: p(i, x)
a = []
for i in range(10):
a.append(makefunc(i))
return a
I was always confused as to why this doesn't work. Thanks for the explanation, 'a paid nerd'. I personally prefer this solution:
for i in range(10):
a.append(lambda num, val_i=i: p (val_i, num))
Note the val_i=i
default argument of the lambda
that enables to capture the instantaneous value of i
during the loop whilst still effectively making lambda
a function of 1 variable. (BTW: changed your x
into num
to match p
's definition.) I like it better because:
functools
Just did a search and found more detailed explanations for the same problem there: Scope of python lambda functions and their parameters
I asked a similar question, and got two answers. One basically the same as the accepted answer here, and the other which is less clear but slightly more succint.
Dynamically creating a menu in Tkinter. (lambda expressions?)
Well you can also bind the i to an outer lambda for the lazy.
def p(x, num):
print x, num
def test():
a = []
for i in range(10):
a.append((lambda i :lambda x: p (i, x))(i))
return a