为什么 `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]
你得到了预期的输出
我在存档中找不到这样的问题。
使用 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]
你得到了预期的输出