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):
a.append(lambda x: p (i, x))
return a
>>> myList = test()
>>> test[0]('test')
9 test
>>> test[5]('test')
9 test
>>> test[9]('test')
9 test
What's going on here?
A function that actually does what I expect the above function to do is:
import functools
def test2():
a = []
for i in range (10):
a.append(functools.partial(p, i))
return a
>>> a[0]('test')
0 test
>>> a[5]('test')
5 test
>>> a[9]('test')
9 test
-
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 samei
variable, which is set to9
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
David : Got it. Thanks very much! -
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.
http://stackoverflow.com/questions/728356/dynamically-creating-a-menu-in-tkinter-lambda-expressions
mataap : Which includes (and I finally understand now) the lambda x=x : ... hack. -
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
0 comments:
Post a Comment