下面的测试失败:
#!/usr/bin/env python
def f(*args):
"""
>>> t = 1, -1
>>> f(*map(lambda i: lambda: i, t))
[1, -1]
>>> f(*(lambda: i for i in t)) # -> [-1, -1]
[1, -1]
>>> f(*[lambda: i for i in t]) # -> [-1, -1]
[1, -1]
"""
alist = [a() for a in args]
print(alist)
if __name__ == '__main__':
import doctest; doctest.testmod()
换一种说法:
>>> t = 1, -1
>>> args = []
>>> for i in t:
... args.append(lambda: i)
...
>>> map(lambda a: a(), args)
[-1, -1]
>>> args = []
>>> for i in t:
... args.append((lambda i: lambda: i)(i))
...
>>> map(lambda a: a(), args)
[1, -1]
>>> args = []
>>> for i in t:
... args.append(lambda i=i: i)
...
>>> map(lambda a: a(), args)
[1, -1]
他们是不同的,因为价值i
在这两个发电机表达和列表比较懒洋洋地评估,即当匿名函数中调用f
。
到那时, i
被绑定到的最后一个值,如果t
,这是-1。
所以基本上,这是该列表理解做什么(同样为genexp):
x = []
i = 1 # 1. from t
x.append(lambda: i)
i = -1 # 2. from t
x.append(lambda: i)
现在lambda表达式随身携带一个封闭引用i
,但i
必然要在这两种情况下-1,因为那是最后一个值就被分配到。
如果你想确保拉姆达接收的电流值i
,做
f(*[lambda u=i: u for i in t])
这样一来,你逼的评价i
在创建关闭的时间。
编辑 :后者泄漏循环变量到周围的范围:有发电机表达式和列表解析之间的一个区别是。
拉姆达捕获变量,不值,因此代码
lambda : i
总是返回我目前在封闭绑定到值。 在调用它的时候,这个值已经被设置为-1。
为了得到你想要的,你需要获得实际的结合在拉姆达创建,由时间:
>>> f(*(lambda i=i: i for i in t)) # -> [-1, -1]
[1, -1]
>>> f(*[lambda i=i: i for i in t]) # -> [-1, -1]
[1, -1]
表达f = lambda: i
等效于:
def f():
return i
表达g = lambda i=i: i
等效于:
def g(i=i):
return i
i
是一个自由变量在第一种情况下,它被绑定到在第二种情况下,即该函数的参数,它是在这种情况下,一个局部变量。 默认参数的值在函数定义的时间进行评估。
发生器表达是最近的封闭范围(其中, i
为被定义) i
在名称lambda
表达,因此i
是在该块中解决的问题:
f(*(lambda: i for i in (1, -1)) # -> [-1, -1]
i
是的局部变量lambda i: ...
块,因此该对象是指在该块中定义:
f(*map(lambda i: lambda: i, (1,-1))) # -> [1, -1]