我想有作为排序缓存一些繁重的计算的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]
该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
。
你看到的是这里的影响倒闭 。 拉姆达从程序捕获状态供以后使用。 因此,尽管每个拉姆达是唯一的对象,状态不一定是唯一的。
实际“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
最后,在一个循环的情况下,循环变量是唯一的“声明”一次。 因此,在循环中的循环变量的任何引用将持续过去的下一次迭代。 这包括在列表解析的变量。
问题是,你不捕获在列表理解的每次迭代i的值,你捕捉变量每次通过。
问题是,一个封闭引用捕获变量。 在这种情况下,要捕获一个变量,其值随时间变化(与所有循环变量),因此它有,当你运行它比你创建时不同的值。
我不知道这是否是一个错误或功能,但有什么情况是, lambda:i
不形成lambda函数之前评估我。 因此,它真的只是其评估无论我的当前值的函数。 下面是如何发生的一个例子。
>>> i=5
>>> x=lambda:i
>>> x()
5
>>> i=6
>>> x()
6
所以,很显然,发生的事情是,除了我同样的事情将要9你的例子,因为它是被通过的范围是0到9的顺序进行分配。
我不认为这没什么,以避免它什么好的办法。 在Python lambda函数是相当有限的。 它不是一个真正的心脏功能的语言。
我不知道你正在尝试用你的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
可能会混淆解析器。 我得到了一些奇怪的错误信息试图运行代码。