我正在学习Python中的lambdas。我需要创建一个函数列表f = [f1, f2...]
,以便每个函数fi(x)
都接收列表x
并返回(x[i]-1)
。
这是我尝试编码的方式,但我得到了惊人的结果。请帮助我理解为什么三个打印件中的每一个都给出不同的结果。最后两个让我绝对难过!
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?!!!
编辑:这个问题与suggested duplicate完全不同。在链接的问题中,有一个简单的错误,用户创建了一个函数列表,而不是函数调用。然而,Tomasz Gandor的答案使用了几个例子来讨论与此处提出的问题相同的问题。
答案 0 :(得分:6)
这是一个常见的问题。您正在寻找的是
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在运行时评估params。 Python将允许你定义这样的东西,它可能会有更多的亮点:
>>> 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
更新 :回复评论中的问题,此示例与原始问题的关联性较小,但有助于更好地了解函数索引评估的发生方式
myvar=1
def f(myvar=myvar):
print myvar
f() # prints 1
f(2) # prints 2
myvar = 5
f() # prints 1
如果您在声明myvar
之前未声明f
,则会获得NameError: name 'myvar' is not defined
。这是因为函数变量的评估是在&#39; compile&#39;时间。 Lambda对运行时的评估,但是当我们提供可选参数时 - 它会立即发生(因此i = i)。希望它提供更清晰的主题:))
答案 1 :(得分:3)
变量i
在全局范围内,在调用任何函数时仍为4
。如果您执行i = 1
,那么您的两个异常输出将变为1 1 1
和[1 1 1 1 1]
我发现这有效:
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。