10

map() 会像“for”那样遍历列表吗?使用 map vs for 有什么价值吗?

如果是这样,现在我的代码如下所示:

for item in items:
    item.my_func()

如果有意义,我想将其设为 map()。那可能吗?一个例子是什么样的?

4

8 回答 8

23

您可以使用map而不是for您显示的循环,但由于您似乎没有使用 的结果item.my_func(),因此不建议这样做。map如果要将没有副作用的函数应用于列表的所有元素,则应使用。在所有其他情况下,请使用显式 for 循环。

此外,从 Python 3.0 开始,map返回一个生成器,因此在这种情况下map将不会表现出相同的行为(除非您明确评估生成器返回的所有元素,例如通过调用list它)。


编辑kibibu在评论中要求澄清为什么map' 的第一个参数不应该是具有副作用的函数。我会尝试回答这个问题:

mapf 意味着在数学意义上传递一个函数。在这种情况下,第二个参数的元素以何种顺序应用并不重要f(当然,只要它们以原始顺序返回)。更重要的是,在这些情况下,在map(g, map(f, l))语义上等同于map(lambda x: g(f(x)), l),无论应用于各自输入的顺序如何fg

map例如,一次返回和迭代器或完整列表都没有关系。但是,如果f和/或g导致副作用,那么只有当 的语义map(g, map(f, l))在任何阶段g应用于由before返回的前n 个元素应用于的(n + 1) st 元素时,才能保证这种等价性。(这意味着必须执行最懒惰的迭代——它在 Python 3 中执行,但在 Python 2 中不是!)map(f, l)map(f, l)flmap

更进一步:即使我们假设 的 Python 3 实现,如果 的输出在提供给外部调用之前被传递map,语义等价可能很容易被打破。map(f, l)itertools.teemap

上面的讨论似乎是理论上的,但随着程序变得越来越复杂,它们变得更难推理,因此也更难调试。确保某些东西是不变的可以在一定程度上缓解这个问题,实际上可以防止一整类错误。

最后,map让许多人想起它在各种(纯)函数式语言中的真正函数式对应物。传递给它一个带有副作用的“函数”会让那些人感到困惑。因此,作为替代方案(即使用显式循环)并不比调用 更难实现map,强烈建议将使用限制map在要应用的函数不会引起副作用的情况下。

于 2009-05-17T19:49:16.990 回答
5

你可以像这样使用 map 来编写它:

map(cls.my_func, items)

将 cls 替换为您正在迭代的项目的类。

正如 Stephan202 所提到的,在这种情况下不建议这样做。

通常,如果您想通过对列表中的每个项目应用某些函数来创建新列表,请使用 map。这意味着该函数没有副作用,因此您可以(可能)并行运行地图。

如果您不想创建新列表,或者该函数有副作用,请使用 for 循环。在您的示例中就是这种情况。

于 2009-05-17T20:00:38.187 回答
2

存在细微的语义差异,这可能在 python 语言规范中是封闭的。该地图是明确可并行的,而在特殊情况下。代码可以从for中跳出,但只能从map中跳出异常。

在我看来, map不应该同时保证函数应用顺序。AFAIK 目前没有 python 实现能够执行此自动并行化。

于 2009-05-17T20:18:55.837 回答
2

如果需要,您可以将 Your 切换map到一些很酷的线程或多处理或分布式计算框架。Disco是基于 erlang-and-python 的分布式、抗故障框架的示例。我将它配置在 2 个 8 核的盒子上,现在我的程序运行速度快了 16 倍,这要归功于 Disco 集群,但是我不得不从列表推导和 for 循环重写我的程序以映射/减少。

使用 for 循环和列表推导以及 map/reduce 编写程序是一样的,但是当您需要它在集群上运行时,如果您使用 map/reduce,您几乎可以免费完成。如果你没有,那么,你将不得不重写。

当心:据我所知,python 2.x 从 map 返回一个列表而不是迭代器。我听说这可以通过使用iter.imap()(虽然从未使用过)来绕过。

于 2009-05-17T21:53:43.283 回答
2

当您不需要返回结果列表(例如具有副作用的函数)时,请使用显式 for 循环。

当您确实需要返回结果列表时(例如,直接根据输入返回值的函数),请使用列表推导式。

当你试图让 Lisp 用户相信 Python 值得使用时,请使用 map()。;)

于 2009-05-18T12:57:04.780 回答
1

的主要优点map是当您想要获取列表中每个元素的某些计算结果时。例如,此代码段将列表中的每个值加倍:

map(lambda x: x * 2, [1,2,3,4])  #=> [2, 4, 6, 8]

重要的是要注意map返回一个带有结果的新列表。它不会修改原始列表。

要对 执行相同的操作for,您必须创建一个空列表并在正文中添加额外的一行,for以将每个计算的结果添加到新列表中。该map版本更加简洁和实用。

于 2009-05-17T19:53:35.110 回答
0

对于内置函数,Map 有时比手动编写 for 循环更快。尝试时序图(str,范围(1000000))与类似的for循环。

于 2009-05-18T22:02:03.713 回答
-3
map(lambda item: item.my_func(), items)
于 2009-05-17T19:48:14.170 回答