Python 中的 Eager 地图

问题描述 投票:0回答:1

在 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 中性能最高的实现是什么作为答案。

python python-3.x functional-programming lazy-evaluation lazy-sequences
1个回答
1
投票

调用

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.
© www.soinside.com 2019 - 2024. All rights reserved.