使用map()和for有价值吗?
map()函数是不是像"for"循环那样遍历列表?使用map和使用for有什么不同吗?
如果是这样的话,我现在的代码是这样的:
for item in items:
item.my_func()
如果可以的话,我想把它改成map()。这样做可以吗?能给个例子吗?
9 个回答
这里有一点语义上的区别,这可能在Python的语言规范中有说明。map是可以明确并行处理的,而for只有在特定情况下才能做到。代码可以在for循环中提前退出,但在map中只能通过抛出异常来逃离。
在我看来,map不应该保证函数应用的顺序,而for则必须保证顺序。根据我所知,目前没有任何Python的实现能够自动进行并行处理。
你可以用 map 这样写:
map(cls.my_func, items)
把 cls 替换成你正在遍历的项目的类名。
正如 Stephan202 提到的,这种做法在这种情况下不推荐。
一般来说,如果你想通过对列表中的每个项目应用某个函数来创建一个新列表,就用 map。这样做的意思是这个函数不会有副作用,因此你可以(有可能)并行运行这个 map。
如果你不想创建新列表,或者这个函数有副作用,就用 for 循环。这就是你例子中的情况。
你可以用 map
来代替你展示的 for
循环,但因为你似乎没有使用 item.my_func()
的结果,所以不推荐这样做。map
适合用在你想对列表中的每个元素应用一个没有副作用的函数时。在其他情况下,还是用普通的 for
循环吧。
另外,从 Python 3.0 开始,map
返回的是一个迭代器,这样的话 map
的表现就不一样了(除非你明确地把迭代器返回的所有元素都计算出来,比如通过调用 list
)。
编辑:kibibu 在评论中询问为什么 map
的第一个参数不应该是有副作用的函数。我来试着回答一下这个问题:
map
是用来传递一个数学意义上的函数 f
。在这种情况下,f
应用到第二个参数的元素的顺序并不重要(只要它们在返回时保持原来的顺序)。更重要的是,在这种情况下,map(g, map(f, l))
和 map(lambda x: g(f(x)), l)
是语义上等价的,无论 f
和 g
是如何应用到它们各自的输入的。
例如,map
是返回一个迭代器还是一次性返回一个完整的列表并不重要。但是,如果 f
和/或 g
造成了副作用,那么只有在 map(g, map(f, l))
的语义是这样的:在任何阶段 g
都是应用到 map(f, l)
返回的前 n 个元素上,然后 map(f, l)
才会对第 (n + 1) 个元素应用 f
。这意味着 map
必须执行最懒惰的迭代——在 Python 3 中是这样做的,但在 Python 2 中不是!
更进一步:即使我们假设 Python 3 的 map
实现,语义上的等价性也可能会因为 map(f, l)
的输出被例如 itertools.tee
处理后再传给外层的 map
调用而轻易破坏。
以上讨论看起来可能有点理论性,但随着程序变得越来越复杂,它们也变得更难以理解,因此调试起来也更困难。确保某些东西是恒定的,能在一定程度上缓解这个问题,甚至可能防止一类错误的发生。
最后,map
让很多人想起它在各种(纯)函数式语言中的真正对应物。如果把一个有副作用的“函数”传给它,会让这些人感到困惑。因此,考虑到替代方案(即使用显式循环)并不比调用 map
更难实现,强烈建议将 map
的使用限制在那些不会造成副作用的函数上。