[英]Why does the following code always output 16?
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
因为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
。
因为你创建的所有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,你可以用这样的闭包做更多的事情
这是违反直觉或至少不太常见的语法。 我想你的意思是:
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)
将打印所有16s。
FFN。 关于破碎的lambda的博客文章: http : //math.andrej.com/2009/04/09/pythons-lambda-is-broken/
这种现象称为lambda绑定,请参阅Python中的“lambda绑定”是什么?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.