map() 方法是否像 "for" 循环一样遍历列表?使用 map() 是否有优势?
如果是这样,那么我的代码现在看起来像这样:
for item in items:
item.my_func()
如果有意义的话,我想将它转换为map()函数。这可行吗?你能给个例子吗?
map() 方法是否像 "for" 循环一样遍历列表?使用 map() 是否有优势?
如果是这样,那么我的代码现在看起来像这样:
for item in items:
item.my_func()
如果有意义的话,我想将它转换为map()函数。这可行吗?你能给个例子吗?
map
代替你展示的for
循环,但由于你似乎没有使用item.my_func()
的结果,所以不建议这样做。如果你想对列表的所有元素应用一个没有副作用的函数,应该使用map
。在其他情况下,请使用显式的for循环。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(f, l)
的语义是这样的:在任何阶段,在 map(f, l)
将 f
应用于 l
的第 *(n + 1)* 个元素之前,g
被应用于 map(f, l)
返回的前 n 个元素。(这意味着 map
必须进行尽可能惰性的迭代——Python 3 中是这样做的,但 Python 2 不是!)
更进一步地说:即使我们假设了 Python 3 版本的 map
实现,如果 map(f, l)
的输出经过 itertools.tee
处理后再提供给外部的 map
调用,语义等价性也很容易破坏。
您可以像这样使用映射来编写代码:
map(cls.my_func, items)
将cls替换为您正在迭代的项目的类。
正如Stephan202所提到的那样,在这种情况下不建议这样做。
一般来说,如果您想通过将某个函数应用于列表中的每个项目来创建一个新的列表,请使用map。这意味着函数没有副作用,因此您可以(潜在地)并行运行map。
如果您不想创建新列表,或者函数具有副作用,请使用for循环。这是您示例中的情况。
这里存在微小的语义差异,这可能在Python语言规范中已经解决。 Map 可以显式地并行化,而 for 只能在特殊情况下并行化。代码可以从 for 中跳出,但只能通过异常从 map 中逃脱。
我认为 map 不应该保证函数应用的顺序,而 for 必须保证。据我所知,目前没有Python实现能够自动并行化。
如果需要,您可以将您的map
切换成一些很棒的线程化、多进程或分布式计算框架。例如,Disco是一个基于Erlang和Python的分布式框架,具有抗故障性。我在两个8核的计算机上配置了它,现在我的程序运行速度快了16倍,这要感谢Disco集群,但是我不得不从列表推导和for循环重写程序到map/reduce。
使用for循环和列表推导和使用map/reduce编写程序没有什么区别,但是当您需要在集群上运行时,如果使用map/reduce,您几乎可以免费完成它。如果没有使用,那么您将不得不进行重写。
注意:据我所知,Python 2.x从map中返回列表而非迭代器。我听说这可以通过使用iter.imap()
来避免(虽然我从未使用过)。
如果您不需要返回结果列表(例如,具有副作用的函数),请使用显式for循环。
如果您需要返回结果列表(例如,基于输入直接返回值的函数),请使用列表推导式。
如果您想说服Lisp用户使用Python,请使用map()。
map
的主要优势在于当您想要获取列表中每个元素的某些计算结果时。例如,此代码段将列表中的每个值都加倍:
map(lambda x: x * 2, [1,2,3,4]) #=> [2, 4, 6, 8]
需要注意的是,map
返回一个包含结果的新列表。它不会直接修改原始列表。
如果使用 for
来完成相同的操作,则需要创建一个空列表,并在 for
循环体中添加一行代码将每次计算的结果添加到新列表中。使用 map
更加简洁和实用。
对于内置函数,使用Map有时比手动编写for循环更快。尝试计时map(str, range(1000000))和类似的for循环。
已经有许多好答案了。我想强调map()
的另一个方面:代码的可读性和透明度。
特别是,我将专注于问题中的这部分内容:
使用
map
与for
相比是否有价值?
map()
而不是循环或推导式,主要的好处是使代码更加透明。list
上操作,并且我假装map()
返回一个list
。[1])map()
转换的列表可以给读者提供额外的信息,并且非常廉价地实现这一点。这些信息分为两类:
map()
,而不是循环或推导式,
>>> def prnt(x): print(f'printing {x}'); return None
>>> a = prnt(1)
printing 1
>>> print(a)
None
# list comprehension:
>>> c = [prnt(x) for x in [1,2]]
printing 1
printing 2
>>> print(c)
[None, None]
# map:
>>> b = map(prnt, [1,2])
# no output - prints nothing!
>>> b # what is it?
<map at 0x11241e290>
>>> l=list(b) # converting to list forces evaluation
printing 1
printing 2
>>> l
[None, None]
map(lambda item: item.my_func(), items)
map
的额外论点,但我不认为Python(目前)执行任何此类优化。) - Stephan202