为什么 `for` 可以迭代对,而 `lambda i,x:` 不能迭代 `map` 对?

Why `for` can iterate pairs, but `lambda i,x:` cannot `map` pairs?

我在存档中找不到这样的问题。

使用 for 可以 解压 迭代对:

>>> for i, x in enumerate([5,10,15]): print('x[%d]=%d' % (i, x))
x[0]=5
x[1]=10
x[2]=15

或者也可以 解压它们:

>>> for x in enumerate([5,10,15]): print(x)
(0, 5)
(1, 10)
(2, 15)

然而,当使用map()时,这个unpack是不可能的:

>>> list(map(lambda i, x: x**i, enumerate([5,10,15])))
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'x'

这是为什么?设计选择?为什么?

我想可以实现这样一个包装器:

def map1(func, *iterables):
    from inspect import signature
    params = signature(func).parameters
    if len(params) == 1:
        yield from map(func, *iterables)
    else:
        yield from map(lambda x: func(*x), *iterables)

(适用于所有情况)

或者另一个,盲目解压参数:

def map2(func, *iterables):
    yield from map(lambda x: func(*x), *iterables)

(我猜后者会惹出一些麻烦)

是否有不这样做的(充分)理由?

这不是 lambda 的问题,而是 map 的问题。 documentation 表示:

If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel.

换句话说,该函数必须采用与您传递的可迭代对象数量相同的参数数量。可迭代对象中每个单独元素的大小不相关。

如果你想将单个可迭代的每个元素作为多个参数传递,你可以使用zip和参数解包以转置序列:

>>> map(lambda i, x: x**i, *zip(*enumerate([5,10,15])))
[1, 10, 225]

正如 Ashwini 指出的那样,您也可以使用 itertools.starmap 而不是 map

这是因为 enumerate() returns 单个枚举对象在多个枚举对象中保存一对值。如果你尝试:

>>> enumerate([5,10,15])
>>> <enumerate at 0x39152d8>
>>>e = enumerate([5,10,15])

>>> for i in e:
    print e

<enumerate object at 0x03915080>
<enumerate object at 0x03915080>
<enumerate object at 0x03915080>

你在他的陈述中做了什么:

map(lambda i, x: x**i, enumerate([5,10,15]))

正在将 enumerate()return 值传递给 lambda。因此,当您指定两个参数时,它只会获得一个值。 如果你尝试:

>>>map(lambda i: i[0] * i[1], enumerate([5,10,15]))
>>> [0,10,30]

你得到了预期的输出