在 Python 中,
map
函数是惰性的,但大多数情况下我需要一个急切的映射。
例如,尝试对地图对象进行切片会导致错误:
>>>> map(abs, [3, -1, -4, 1])[1:]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'map' object is not subscriptable (key slice(1, None, None))
我想我需要自己实现一个 eager map,所以我想知道在 Python 中是否有一种标准的方法。
我设法以几种不同的方式实现它,但我不确定应该首选哪种替代方案。我要求同时使用 CPython 和 PyPy3,如果答案因 Python 实现而异,我更愿意了解所有相关选项。
这些是我的实现:
def eager_map_impl0(f, *collections):
return list(map(f, *collections))
def eager_map_impl1(f, *collections):
return [x for x in map(f, *collections)]
def eager_map_impl2(f, *collections):
return [*map(f, *collections)]
def eager_map_impl3(f, *collections):
return [f(*x) for x in zip(*collections)]
用法示例:
>>>> eager_map_impl0(abs, [3, -1, -4, 1])[1:]
[1, 4, 1]
>>>> eager_map_impl1(abs, [3, -1, -4, 1])[1:]
[1, 4, 1]
>>>> eager_map_impl2(abs, [3, -1, -4, 1])[1:]
[1, 4, 1]
>>>> eager_map_impl3(abs, [3, -1, -4, 1])[1:]
[1, 4, 1]
关于重复投票,链接的问题和它的一些答案很有趣,但我认为不是这里的答案。我已经知道我想使用
map
,而不是列表理解;所以我希望有人会在这里说出 CPython 与 Pypy 中性能最高的实现是什么作为答案。
调用
list(map(...))
,就像你的第一个例子一样,足以满足你的需求,你甚至不需要另一个函数来包装它——因为它的意图很明显。
在这种情况下使用列表与理解的性能差异应该是最小的,但在列表方面有优势,因为不需要执行 Python VM 操作 - 列表构建器将直接在地图迭代器中调用
__next__
本机代码。对于 Pypy 来说,这是不可预测的,因为对于足够长的有意义的序列,JIT 将被触发,并且它可能有自己的方式。 (无论如何,差异应该无关紧要)
现在,有时,在映射函数执行 I/O 或具有其他副作用的情况下,人们可能只想应用
map
而 not 存储结果。在这种情况下,最佳性能方法几乎没有记录:maxlen 为 0 的 collections.deque
结构实际上在内部优化以消耗迭代器中的所有项目,并将处理您的所有项目:
from collections import deque
...
deque(map(function, items), maxlen=0) # <- process everyone and throws away the return values.