关于python:为什么这个简单的lambda函数会产生奇怪的输出?

Why is this simple lambda function giving bizarre outputs?

本问题已经有最佳答案,请猛点这里访问。

我在学Python。我需要创建一个函数f = [f1, f2...]的列表,以便每个函数fi(x)接受一个列表x并返回(x[i]-1)

这就是我尝试编码它的方式,但我得到了令人惊讶的结果。请帮助我理解为什么这三张照片的效果各不相同。最后两个都让我很难堪!

1
2
3
4
5
6
7
8
f = [(lambda x: x[i]-1) for i in range(5)]
# I expect f to be [ (lambda x: x[0]-1), (lambda x: x[1]-1), ...]

x = [1, 2, 3, 4, 5]

print f[0](x), f[1](x), f[2](x)    # output: 4 4 4 !!
print [f[i](x) for i in range(5)]  # output: [0, 1, 2, 3, 4] as expected
print [f[k](x) for k in range(5)]  # output: [4, 4, 4, 4, 4] wha?!!!

编辑:这个问题与建议的副本有很大不同。在链接的问题中,有一个简单的错误,用户创建了函数列表,而不是函数调用。然而,Tomasz Gandor的回答使用几个例子讨论了与这里所问的相同的问题。


这是一个常见的问题。你要找的是

1
2
3
4
f = [(lambda x, i=i: x[i]-1) for i in range(5)]
z = [1,2,3,4,5]
print f[0](z),f[1](z),f[2](z)
0 1 2

您的列表理解创建了5个函数,这些函数都指向i。循环结束时,i等于4。因此,不管您叫什么lambda,它都将i计算为4。

要将当前的i值赋给lambda函数的局部变量。您可以使用可选参数来执行此操作。

lambda在运行时计算参数。python允许您定义这样的东西,它可能会释放更多的光:

1
2
3
4
5
6
7
8
9
10
>>> f = lambda x: x[i] - 1
>>> l = [1, 2, 3, 4]
>>> f(l)

Traceback (most recent call last):
  File"<pyshell#91>", line 1, in <module>
    f(l)
  File"<pyshell#89>", line 1, in <lambda>
    f = lambda x: x[i] - 1
IndexError: list index out of range

更新:回答来自注释的问题时,此示例与原始问题的相关性较小,但有助于更好地理解函数参数评估是如何发生的。

1
2
3
4
5
6
7
8
9
myvar=1

def f(myvar=myvar):
    print myvar

f()  # prints 1
f(2) # prints 2
myvar = 5
f()  # prints 1

如果你在申报f之前没有申报myvar,你会得到NameError: name 'myvar' is not defined。这是因为函数变量是在"编译"时计算的。lambda在运行时进行计算,但当我们提供可选参数时,它会立即发生(因此i=i)。希望它能提供更清晰的主题:)


变量i在全局范围内,调用任何函数时仍然是4。如果你做i = 1,那么你的两个异常输出将变成1 1 1[1 1 1 1 1]

我发现这个作品:

1
2
3
g = lambda i: lambda x: x[i] - 1
f = [ g(i) for i in range(5) ]  # i missed here
print [f[k]([1,2,3,4,5]) for k in range(5)] # [0, 1, 2, 3, 4]

i现在的作用域是第二个lambda。