python map vs itertools.map:使迭代器版本表现得像前者
Posted
技术标签:
【中文标题】python map vs itertools.map:使迭代器版本表现得像前者【英文标题】:python map vs itertools.map: Make the iterator version behave like the former 【发布时间】:2012-12-14 22:05:38 【问题描述】:考虑以下示例代码。给出这个例子只是为了强调map
和itertools.imap
之间的不同功能。我真正想做的不可能是
完成列表理解,因为在我的真正问题中,我不是创建一个列表,而是用小数组填充一个更大的 numpy 数组。所以响应下面的代码,请不要提示:[f(x) for x in range(3)]
例子:
g = []
def f(x):
g.append(x)
我使用map
和 itertools.map 得到的结果:
map(f, range(3)) # Results in g = [0,1,2]
itertools.imap(f, range(3)) # Does not change g
我希望 g
像 map
函数所做的那样进行更改。
但是,我听说map
会(或确实)表现得像
itertools.imap
在 Python 3 中。即使我使用的是 Python 2.7,我也想学习使用迭代器版本的地图的正确方法。如何使用itertools.imap
实现
与map
得到的结果相同?
我能做到:
b = itertools.imap(f, range(3))
list(b) # This gives g = [0,1,2] if starting with an empty g.
这是正确的方法,还是有更好的方法?
提前致谢。
【问题讨论】:
【参考方案1】:itertools
函数返回生成器;它们仅在迭代时运行。所以 itertools.imap(f, range(3))
实际上不会做任何事情,直到你运行它完成,例如list
。
根据http://docs.python.org/2/library/itertools.html#recipes,使用迭代器的最有效方式是使用长度为零的双端队列:
collections.deque(itertools.imap(f, range(3)), maxlen=0)
但是,如果你调用一个函数是为了它的副作用,你应该使用命令式而不是函数式语法:
for i in range(3):
f(i)
【讨论】:
感谢有关 collections.deque() 的信息和有关循环的提示。我会调查的。在这种情况下,我不能使用循环,因为我最终想使用 picloud,如果我想同时运行作业(列表中的每个值一个作业),这需要我使用 cloud.map。我知道 cloud.map 与内置地图不同。但是,我想保持本地版本的代码和我在 picloud 上运行的相似。只是为了确保我以后可以在需要时使用 cloud.map。另外,map 不是比 for 循环快吗? 我不同意总是使用显式循环,如果性能相关,map
、imap
和列表推导的隐式循环会更快。
@Curious2learn 不,没有理由假设 map 比 for 循环更快(例如,map
需要收集其结果,即使它们立即被丢弃)。我会谨慎申请cloud.map
;它的全局变量可变性方法可能不适用于您对 g
的修改。
@ecatmur python.org/doc/essays/list2str.html - 根据 BDFL,C 中的隐式循环确实提供了性能优势。
@l4mpi 这是一个非常特殊的情况,其中查找循环函数的开销支配了调用开销。不过,要点是。【参考方案2】:
您错误地使用了map()
。它不应用于函数调用的副作用,而应用于转换可迭代对象。
您可以使用list(itertools.imap(f, range(3)))
来获得您想要的行为,但我认为您应该更改整个方法以使用普通的 for 循环:
for i in range(3):
f(i)
这表明 f()
调用的返回值没有被使用。
【讨论】:
据我所知itertools.imap
和map
一样,使用隐式循环,应该比显式循环更快。【参考方案3】:
不同之处在于 Python 2.x 中的 map
相当于 Python 3 中的 list(map(...))
。就是这样 - 没什么特别的......
【讨论】:
以上是关于python map vs itertools.map:使迭代器版本表现得像前者的主要内容,如果未能解决你的问题,请参考以下文章
Flux 和 Mono 中的 compose() vs. transform() vs. as() vs. map()