当前位置: 首页 > 面试题库 >

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

姬存
2023-03-14
问题内容

以下测试失败:

#!/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生成器表达式和list comp中的值都是惰性计算的,即在中调用匿名函数时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,因为这是为其分配的最后一个值。

如果要确保lambda接收到的当前值i,请执行

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

这样,您i可以在创建闭包时强制进行评估。

编辑 :生成器表达式和列表推导之间有一个区别:后者将循环变量泄漏到周围的范围内。



 类似资料:
  • 我知道什么是mapPartition转换和map。一些帖子声称mapPartition比map快。在什么情况下,我们使用mapPartition而不是map?mapPartition比map快吗?

  • 问题内容: 首先,我的Java版本: 输出为: 31 -117 8 0 0 0 0 0 0 -53 72 -51 -55 -55 47 -49 47 -54 73 1 0 -83 32 -21 -7 10 0 0 0 然后是Go版本: 输出: 31 139 8 0 0 9 110 136 0 255 202 72 205 201 201 47 207 47 202 73 1 0 0 0 255 2

  • 问题内容: 为什么更改总和顺序会返回不同的结果? = = 双方的Java和JavaScript的返回相同的结果。 我知道,由于以二进制表示浮点数的方式,某些有理数( 例如1/3-0.333333 … )无法精确表示。 为什么简单地更改元素的顺序会影响结果? 问题答案: 也许这个问题很愚蠢,但是为什么仅仅改变元素的顺序会影响结果呢? 它将根据值的大小更改四舍五入的点。作为示例 _样的_事情,我们所看

  • 为什么改变求和顺序会返回不同的结果? = Java和JavaScript都返回相同的结果。 我知道,由于浮点数在二进制中的表示方式,一些有理数(如1/3-0.333333...)不能精确表示。 为什么简单地改变元素的顺序会影响结果?

  • 我理解为0.1d+0.2d~=0.300000000000000004。 但我猜这些结果是相同的,但事实并非如此。 为什么结果不同?

  • 我目前正在转换一个脚本从Python 2到Python 3。在调试时,我偶然发现了两个版本之间行为不同的部分代码。然而,我无法解释这种差异。 这是一台复制机: Python 2.7.18显示以下输出: 而Python 3.9.0则显示: 为什么第一个列表理解在Python 3中不起作用?为什么它在变量中存储的内容时工作?