这里发生了什么?我正在尝试创建一个函数列表:
def f(a,b):
return a*b
funcs = []
for i in range(0,10):
funcs.append(lambda x:f(i,x))
这不符合我的期望。我希望列表的行为如下:
funcs[3](3) = 9
funcs[0](5) = 0
但是列表中的所有函数似乎都是相同的,并且将固定值设置为9:
funcs[3](3) = 27
funcs[3](1) = 9
funcs[2](6) = 54
有什么想法吗?
答案 0 :(得分:19)
python中的lambdas是闭包....你给它的参数在评估lambda之前不会被评估。那时候i = 9,因为你的迭代已经完成了。
您正在寻找的行为可以通过functools.partial
来实现import functools
def f(a,b):
return a*b
funcs = []
for i in range(0,10):
funcs.append(functools.partial(f,i))
答案 1 :(得分:13)
是的,通常的“范围问题”(实际上是一个绑定 - 后来比你想要的问题,但它经常被这个名称调用)。你已经得到了两个最好的(因为最简单的)答案 - “假默认”i=i
解决方案和functools.partial
,所以我只给出经典三个中的第三个,“工厂lambda“:
for i in range(0,10):
funcs.append((lambda i: lambda x: f(i, x))(i))
如果i=i
中的函数没有被2个参数而不是1个意外调用的风险,我个人会选择funcs
,但是当你需要的时候工厂函数方法值得考虑比预先绑定一个arg更富有。
答案 2 :(得分:11)
只有一个i
绑定到每个lambda,与你的想法相反。这是一个常见的错误。
获得所需内容的一种方法是:
for i in range(0,10):
funcs.append(lambda x, i=i: f(i, x))
现在,您在每个lambda闭包中创建一个默认参数i
,并将循环变量i
的当前值绑定到它。
答案 3 :(得分:2)
所有的lambdas最终都被绑定到最后一个。请参阅此问题以获得更长的答案:
How do I create a list of Python lambdas (in a list comprehension/for loop)?
答案 4 :(得分:2)
考虑i == 9
与任何好的python函数一样,它将在定义的范围内使用变量的值。也许lambda: varname
(因为它是一种语言结构)绑定到名称而不是值,并在运行时评估该名称?
类似于:
i = 9
def foo():
print i
i = 10
foo()
我很想知道我的答案是否正确