为什么尝试创建curried函数列表不起作用?
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
这里发生了什么?
实际执行我期望上述功能的功能是:
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
答案 0 :(得分:12)
在Python中,在循环和分支中创建的变量不是作用域。您使用lambda
创建的所有函数都引用了相同的i
变量,该变量在循环的最后一次迭代时设置为9
。
解决方案是创建一个返回函数的函数,从而确定迭代器变量的范围。这就是functools.partial()
方法有效的原因。例如:
def test():
def makefunc(i):
return lambda x: p(i, x)
a = []
for i in range(10):
a.append(makefunc(i))
return a
答案 1 :(得分:1)
那么你也可以将i绑定到懒惰的外部lambda。
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
答案 2 :(得分:1)
我一直很困惑为什么这不起作用。感谢您的解释,'a paid nerd'。我个人更喜欢这个解决方案:
for i in range(10):
a.append(lambda num, val_i=i: p (val_i, num))
注意val_i=i
的{{1}}默认参数,它允许在循环期间捕获lambda
的瞬时值,同时仍然有效地使i
成为1变量的函数。 (顺便说一句:将lambda
更改为x
以匹配num
的定义。)我更喜欢它,因为:
p
刚刚进行了搜索并找到了有关同一问题的更详细解释:Scope of python lambda functions and their parameters
答案 3 :(得分:0)
我问了一个类似的问题,得到了两个答案。一个与这里接受的答案基本相同,另一个不太清楚,但稍微更加苛刻。
Dynamically creating a menu in Tkinter. (lambda expressions?)