TL;DR map函数及其类似函数在python2和python3下表现差异很大,py2下返回list,而py3下返回迭代器。解决办法是使用list函数显式求值。
下面是关于map函数的代码示例,透过在python2和python3不同行为,为你展现不同:
导入相关模块
import time
定义我们的task函数,通过打印输出让我们了解实际工作情况
def task(x):
print("round: {}, I am start to sleep".format(x))
time.sleep(1)
print("round: {}, I am finished sleep".format(x))
return pow(x, 2)
将可迭代对象map到task函数
map(task, range(4))
python2中的map函数
在python2中执行以上代码,可以得到如下输出:
round: 0, I am start to sleep
round: 0, I am finished sleep
round: 1, I am start to sleep
round: 1, I am finished sleep
round: 2, I am start to sleep
round: 2, I am finished sleep
round: 3, I am start to sleep
round: 3, I am finished sleep
[0, 1, 4, 9]
python3中的map函数
在python3中执行以上代码,可以得到如下输出:
<map at 0x7f9df0559b00>
很不幸,你的task代码并没有执行,无论是打印输出还是返回值,都没有执行。 那是因为python2中的map是Apply function to every item of iterable and return a list of the results.而python3中的map是Return an iterator that applies function to every item of iterable, yielding the results.
这个例子中,使用了交互式编程,用户可以直观的看到返回结果,但是在非交互式使用场景(比如作为模块运行)时,如果没有收集返回值也没有类似打印输出的情况下,一切看似正常,但实际没有运行的情况,将造成难以调试的bug。
解决不同
如何才能让python3的map函数的行为和python2的一样呢?
答案是使用list函数,将上述代码稍作改动:
list(map(task, range(4)))
那么你将得到输出:
round: 0, I am start to sleep
round: 0, I am finished sleep
round: 1, I am start to sleep
round: 1, I am finished sleep
round: 2, I am start to sleep
round: 2, I am finished sleep
round: 3, I am start to sleep
round: 3, I am finished sleep
[0, 1, 4, 9]
这将和python2一模一样。
更大范围的不同
很不幸的是python2和python3的差异不仅仅在一个map函数上,很多函数也存在类似的差异,如multiprocessing
模块的Pool
类的imap_unordered
和map
方法,实际上python2和python3差异还是比较大的,所以如果遇到兼容性问题,第一件事情就是立即查阅官方文档。