繁体   English   中英

为什么以下代码总是输出16?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM