列表内涵里面Lambda表达式(Lambdas inside list comprehensions

2019-06-23 12:06发布

我想有作为排序缓存一些繁重的计算的lambda表达式的列表,并注意到了这一点:

>>> [j() for j in [lambda:i for i in range(10)]]
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]

虽然

>>> list([lambda:i for i in range(10)])
[<function <lambda> at 0xb6f9d1ec>, <function <lambda> at 0xb6f9d22c>, <function <lambda> at 0xb6f9d26c>, <function <lambda> at 0xb6f9d2ac>, <function <lambda> at 0xb6f9d2ec>, <function <lambda> at 0xb6f9d32c>, <function <lambda> at 0xb6f9d36c>, <function <lambda> at 0xb6f9d3ac>, <function <lambda> at 0xb6f9d3ec>, <function <lambda> at 0xb6f9d42c>]

这意味着lambda表达式是唯一的功能,但它们在某种程度上都有着相同的索引值。

这是一个错误或功能? 如何避免这个问题? 它不限于列出内涵......

>>> funcs = []
... for i in range(10):
...     funcs.append(lambda:i)
... [j() for j in funcs]
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]

Answer 1:

lambda返回的值, i在你怎么称呼它的时候。 既然你调用lambda循环完成后运行,值i将永远是9。

您可以创建一个本地i在λ变量的时间来保存值lambda的定义:

>>> [j() for j in [lambda i=i:i for i in range(10)]]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

另一种解决方案是创建一个返回函数lambda

def create_lambda(i):
    return lambda:i
>>> [j() for j in [create_lambda(i) for i in range(10)]]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

这工作,因为有不同的闭合(持有不同的价值i的每个调用创建) create_lambda



Answer 2:

你看到的是这里的影响倒闭 。 拉姆达从程序捕获状态供以后使用。 因此,尽管每个拉姆达是唯一的对象,状态不一定是唯一的。

实际“gotchya”这里,是变量i被捕获,而不是该值i表示在该时间点。 我们可以用更简单的例子说明这一点:

>>> y = 3
>>> f = lambda: y
>>> f()
3
>>> y = 4
>>> f()
4

拉姆达持有的参考变量,并评估该变量当你执行拉姆达。

要解决这个问题,你可以分配到拉姆达中的局部变量:

>>> f = lambda y=y:y
>>> f()
4
>>> y = 6
>>> f()
4

最后,在一个循环的情况下,循环变量是唯一的“声明”一次。 因此,在循环中的循环变量的任何引用将持续过去的下一次迭代。 这包括在列表解析的变量。



Answer 3:

问题是,你不捕获在列表理解的每次迭代i的值,你捕捉变量每次通过。

问题是,一个封闭引用捕获变量。 在这种情况下,要捕获一个变量,其值随时间变化(与所有循环变量),因此它有,当你运行它比你创建时不同的值。



Answer 4:

我不知道这是否是一个错误或功能,但有什么情况是, lambda:i不形成lambda函数之前评估我。 因此,它真的只是其评估无论我的当前值的函数。 下面是如何发生的一个例子。

>>> i=5
>>> x=lambda:i
>>> x()
5
>>> i=6
>>> x()
6

所以,很显然,发生的事情是,除了我同样的事情将要9你的例子,因为它是被通过的范围是0到9的顺序进行分配。

我不认为这没什么,以避免它什么好的办法。 在Python lambda函数是相当有限的。 它不是一个真正的心脏功能的语言。



Answer 5:

我不知道你正在尝试用你的lambda函数做。 它不带任何参数...

我认为,Python是制作类似于发生器(i for i in range(10))然后迭代这一点。 它计算10次后,终值i是9,然后就是什么拉姆达函数返回。

你想使某种物体,将产生了在[0,9]的数字? 因为如果你想这样做,只是使用xrange(10)它返回产生凑数[0,9]的迭代器。

def f(x):
    return x

lst = [f(x) for x in xrange(10)]
print(lst == range(10))  # prints True

注:我认为这是一个非常糟糕的主意,试图命名功能j() Python使用j指示复数的虚部,我觉得一个功能名为j可能会混淆解析器。 我得到了一些奇怪的错误信息试图运行代码。



文章来源: Lambdas inside list comprehensions