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)