使用以下语法
读回有关堆栈溢出的问题In [1]: [lambda: x for x in range(5)][0]()
Out[1]: 4
In [2]: [lambda: x for x in range(5)][2]()
Out[2]: 4
但是我很难理解为什么这个输出恰好是4, 我的理解是它总是将列表的最后一个值作为输出,
In [4]: [lambda: x for x in [1,5,7,3]][0]()
Out[4]: 3
但仍不相信此语法如何以最后一个值结束。
如果我能对这种语法得到正确的解释,那将非常高兴
答案 0 :(得分:15)
这不是关于列表推理还是lambdas。这是关于Python中的范围规则。让我们将列表理解重写为等效循环:
funcs = []
for x in range(5):
def f(): return x
funcs.append(f)
funcs[0]() # returns 4
在这里,我们可以看到我们连续构造函数并将它们存储在列表中。当调用其中一个函数时,所有发生的事情都是查找并返回x
的值。但x
是一个值变化的变量,因此4
的最终值是总是返回的值。您甚至可以在循环后更改x
的值,例如,
x = 32
funcs[2]() # returns 32
为了获得您期望的行为,Python需要将for
内容作为块进行范围化;它没有。通常,这不是问题,并且很容易解决。
答案 1 :(得分:4)
对于具有n次迭代的LC,x
被分配源序列的元素0到n-1。在最后一次迭代中,x
被赋予最后一个元素。需要注意的是,总是相同的x
,并且最后调用函数会返回最后持有的x
。
答案 2 :(得分:3)
让我打破我理解的代码
In [39]: [lambda: x for x in [1,5,7,3]]
Out[39]:
[<function <lambda> at 0x2cd1320>,
<function <lambda> at 0x2cd12a8>,
<function <lambda> at 0x2cd10c8>,
<function <lambda> at 0x2cd1050>]
上面的给出了函数列表
In [40]: [lambda: x for x in [1,5,7,3]][1]
Out[40]: <function <lambda> at 0x2cd1488>
索引1从函数列表中提供1个函数。
现在这个函数将应用于x,它始终是list的最后一个值。多数民众赞成总是给出最后一个值。
就像下面的代码一样。
In [41]: [lambda: 2][0]()
Out[41]: 2
In [42]: alist = [1,5,7,3,4,5,6,7]
对于[1,5,7,3]中的x,x对等于函数f(x)。
和In [43]: def f(x):
....: for x in alist:
....: pass
....: return x
In [44]: print f(alist)
7
答案 3 :(得分:1)
这将解决它:
[(lambda(i): lambda: i)(x) for x in range(5)][2]()
问题是你没有在列表推导的每次迭代中捕获x的值,你每次都在捕获变量。
答案 4 :(得分:1)
正如其他人所说,你遇到了常见的循环闭包问题;即闭包通过引用捕获变量的问题。在这种情况下,您将捕获一个值随时间变化的变量(与所有循环变量一样),因此它在运行时的值与创建时的值不同。
要完成您想要的任务,您需要在创建lambda时捕获变量的值。 sblom建议将其包装在一个立即执行的函数中的解决方案:
[(lambda(i): lambda: i)(x) for x in range(5)][2]()
您经常在Python中看到的另一个解决方案是使用默认参数,它还会在创建时评估值:
[lambda i=x: i for x in range(5)][2]()
(它通常写成lambda x=x: x
,但为了清晰起见我重命名了变量)