奇怪的行为:Lambda内部列表理解

Gen*_*cos 18 python lambda list-comprehension

在python 2.6中:

[x() for x in [lambda: m for m in [1,2,3]]]
Run Code Online (Sandbox Code Playgroud)

结果是:

[3, 3, 3]
Run Code Online (Sandbox Code Playgroud)

我希望输出为[1,2,3].即使使用非列表理解方法,我也会得到完全相同的问题.甚至在我将m复制到另一个变量之后.

我错过了什么?

unu*_*tbu 16

要使lambda记住值m,可以使用带有默认值的参数:

[x() for x in [lambda m=m: m for m in [1,2,3]]]
# [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为默认值在定义时设置一次.每个lambda现在使用自己的默认值,m而不是m在lambda执行时在外部作用域中查找值.


Sin*_*ion 6

您遇到的效果称为闭包,当您定义一个引用非局部变量的函数时,该函数会保留对该变量的引用,而不是获取自己的副本.为了说明,我将您的代码扩展为没有理解或lambdas的等效版本.

inner_list = []
for m in [1, 2, 3]:
    def Lambda():
         return m
    inner_list.append(Lambda)
Run Code Online (Sandbox Code Playgroud)

所以,在这一点上,它inner_list有三个函数,每个函数在被调用时都会返回值m.但突出的一点是,他们都看到了相同m,即使m正在改变,他们也不会看到它,直到稍后再打电话.

outer_list = []
for x in inner_list:
    outer_list.append(x())
Run Code Online (Sandbox Code Playgroud)

特别是,由于内部列表完全在外部列表开始构建之前构建,m因此已经达到其最后一个值3,并且所有三个函数都看到相同的值.


g.d*_*d.c 5

长话短说,你不想这样做.更具体地说,您遇到的是操作顺序问题.你正在创建三个单独lambda的返回m,但没有一个立即被调用.然后,当你到达外部列表理解并且它们都被称为剩余值为m3时,内部列表理解的最后一个值.

- 征求意见 -

>>> [lambda: m for m in range(3)]
[<function <lambda> at 0x021EA230>, <function <lambda> at 0x021EA1F0>, <function <lambda> at 0x021EA270>]
Run Code Online (Sandbox Code Playgroud)

这是三个独立的lambdas.

并且,作为进一步的证据:

>>> [id(m) for m in [lambda: m for m in range(3)]]
[35563248, 35563184, 35563312]
Run Code Online (Sandbox Code Playgroud)

同样,三个独立的ID.