def makeActions():
acts=[]
for i in range(5):
print len(acts)
acts.append(lambda x: i ** x)
print acts[i]
return acts
acts=makeActions()
for i in range(5):
print acts[i](2)
输出:
16
16
16
16
16
预期产出:
0
1
4
9
16
答案 0 :(得分:23)
因为lambda中的i
可能不是您所期望的。要验证这一点,请更改代码:
acts.append(lambda x: (i, i ** x))
现在print
会告诉您i
的价值:
(4, 16)
(4, 16)
(4, 16)
(4, 16)
(4, 16)
这意味着lambda
不会复制i
的值,而是保留对变量的引用,因此所有lambda
都会看到相同的值。要解决此问题,请复制i
:
acts.append(lambda x, i=i: (i, i ** x))
小i=i
在i
内创建lambda
的本地副本。
[编辑]现在为什么这样?在2.1之前的Python版本中,本地函数(即在其他函数内定义的函数)无法在同一范围内看到变量。
def makeActions():
acts=[]
for i in range(5):
print len(acts)
def f(x): # <-- Define local function
return i ** x
acts.append(f)
print acts[i]
return acts
然后你会收到i
未定义的错误。 lambda
可以看到封闭的范围,代价是语法稍差。
此行为已在最新版本的Python(2.5,IIRC)中修复。使用这些旧版本的Python,您必须编写:
def f(x, i=i): # <-- Must copy i
return i ** x
自修复(请参阅PEP 3104)以来,f()
可以查看同一范围内的变量,因此不再需要lambda
。
答案 1 :(得分:6)
因为你创建的所有lambda函数都绑定到i,它在循环结束时变为4,并且我们都知道4 * 4 = 16
避免使用嵌套函数(闭包)创建函数,例如
def makePowerFunc(base):
def powerFunc(x):
return base**x
return powerFunc
def makeActions():
acts=[]
for i in range(5):
acts.append(makePowerFunc(i))
return acts
acts=makeActions()
for i in range(5):
print acts[i](2)
<强>输出:强>
0
1
4
9
16
还有其他方法可以解决它,但最好有一个命名的嵌套函数而不是lambda,你可以用这样的闭包做更多的事情
答案 2 :(得分:5)
这是违反直觉或至少不太常见的语法。我想你的意思是:
acts.append(lambda x, i = i: i ** x)
将输出:
0
1
4
9
16
FN。在你的版本中,
acts.append(lambda x, i: i ** x)
创建了lambda函数,但它们都引用了循环中的本地i
,它停在i = 4
,所以你的所有lambdas都说:lambda x: 4 ** x
,因此
for i in range(5):
print acts[i](2)
将打印所有16个。
FFN。关于破损lambda的博客文章:http://math.andrej.com/2009/04/09/pythons-lambda-is-broken/
答案 3 :(得分:3)
这种现象称为lambda绑定,请参阅What is "lambda binding" in Python?