代码之家  ›  专栏  ›  技术社区  ›  jfs

为什么map()和列表理解的结果不同?

  •  11
  • jfs  · 技术社区  · 18 年前

    #!/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]
    
    3 回复  |  直到 18 年前
        1
  •  9
  •   Torsten Marek    18 年前

    它们是不同的,因为 i f .
    到那时,, 我 t ,即-1。

    因此,基本上,这就是列表理解的作用(同样适用于genexp):

    x = []
    i = 1 # 1. from t
    x.append(lambda: i)
    i = -1 # 2. from t
    x.append(lambda: i)
    

    现在lambda带有一个引用 我 在这两种情况下都绑定到-1,因为这是最后一个指定给它的值。

    做

    f(*[lambda u=i: u for i in t])
    

    我 在创建闭包时。

    :生成器表达式和列表理解之间有一个区别:后者将循环变量泄漏到周围的范围中。

        2
  •  6
  •   Brian    18 年前

    lambda捕获变量,而不是值,因此代码

    lambda : i
    

    将始终返回i为的值 在闭包时一定要打开。在调用它时,该值已设置为-1。

    要获得所需内容,您需要通过以下方式在创建lambda时捕获实际绑定:

    >>> 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]
    
        3
  •  4
  •   jfs    18 年前

    f = lambda: i

    def f():
        return i
    

    表示 g = lambda i=i: i

    def g(i=i):
        return i
    

    i free variable

    生成器表达式是最近的封闭范围(其中 我 定义)用于 姓名 lambda 因此,表达 我

    f(*(lambda: i for i in (1, -1)) # -> [-1, -1]
    

    我 是的局部变量 lambda i: ...

    f(*map(lambda i: lambda: i, (1,-1))) # -> [1, -1]