为什么地图的结果()和列表理解有什么不同?(Why results of map() and lis

2019-07-17 11:06发布

下面的测试失败:

#!/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]

Answer 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在创建关闭的时间。

编辑 :后者泄漏循环变量到周围的范围:有发电机表达式和列表解析之间的一个区别是。



Answer 2:

拉姆达捕获变量,不值,因此代码

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]


Answer 3:

表达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]


文章来源: Why results of map() and list comprehension are different?