Python 为什么下面的代码总是输出16?
输出:Python 为什么下面的代码总是输出16?,python,Python,输出: 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 因为lambda中的
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
因为lambda中的
i
可能不是您所期望的。要验证这一点,请更改代码:
0
1
4
9
16
现在,print
告诉您i
的值:
acts.append(lambda x: (i, i ** x))
(4, 16)
(4, 16)
(4, 16)
(4, 16)
(4, 16)
这意味着lambda
不会复制i
的值,而是保留对变量的引用,因此所有lambda
都会看到相同的值。要解决此问题,请复制i
:
acts.append(lambda x: (i, i ** x))
(4, 16)
(4, 16)
(4, 16)
(4, 16)
(4, 16)
小i=i
在lambda
内创建i
的本地副本
[编辑]这是为什么?在Python 2.1之前的版本中,本地函数(即在其他函数中定义的函数)无法看到相同范围内的变量
acts.append(lambda x, i=i: (i, i ** x))
由于修复(请参见),
f()
可以看到相同范围内的变量,因此不再需要lambda
。因为您创建的所有lambda函数都绑定到i,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)
还有其他方法可以解决这个问题,但是最好使用一个命名的嵌套函数而不是lambda,而且使用这种闭包可以做更多的事情这是违反直觉的,或者至少是不太常见的语法。我猜你的意思是:
0
1
4
9
16
这将输出:
acts.append(lambda x, i = i: i ** x)
fn。在你的版本中
0
1
4
9
16
创建了lambda函数,但它们都引用了循环中的本地i
,该循环在i=4
处停止,因此所有lambda都说:lambda x:4**x
,因此
acts.append(lambda x, i: i ** x)
将打印所有16个字符
ffn。一篇关于损坏的lambda的博客文章:这种现象被称为lambda绑定,请参见,因为代码可能就是这么说的?你必须澄清你的期望,然后有人会告诉你你做错了什么。我不知道
16
是怎么出来的……我编辑了你的问题,给你一个未来如何改进它们的想法:-)哇。那么为什么我在第一个例子中总是4?创建lambda时创建本地副本不是很自然吗?现在它也在复制,但在一个奇怪的地方。因为第一个lambda获得了对循环变量i
的引用。事实上,lambda代码中的i
与for
中的i
非常相同。随着循环变量的更改,对它的所有引用也会更改。当您在函数/lambda定义中说i=i
时,您会说:创建一个新参数,并使用循环变量i
+1的当前值对其进行初始化,只是为了修复实际和预期输出的坏问题。
for i in range(5):
print acts[i](2)