map函数与相似函数在python2和python3中的不同

TL;DR map函数及其类似函数在python2和python3下表现差异很大,py2下返回list,而py3下返回迭代器。解决办法是使用list函数显式求值。

下面是关于map函数的代码示例,透过在python2和python3不同行为,为你展现不同:

导入相关模块

import time
`</pre>

定义我们的task函数,通过打印输出让我们了解实际工作情况

<pre>`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)
`</pre>

将可迭代对象map到task函数

<pre>`map(task, range(4))
`</pre>

## python2中的map函数

在python2中执行以上代码,可以得到如下输出:

<pre>`    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]
`</pre>

## python3中的map函数

在python3中执行以上代码,可以得到如下输出:

<pre>`    /&lt;map at 0x7f9df0559b00/&gt;
`</pre>

很不幸,你的task代码并没有执行,无论是打印输出还是返回值,都没有执行。
那是因为python2中的map是[Apply function to every item of iterable and return a list of the results.](https://docs.python.org/2/library/functions.html#map)而python3中的map是[Return an iterator that applies function to every item of iterable, yielding the results.](https://docs.python.org/3/library/functions.html#map)

这个例子中,使用了交互式编程,用户可以直观的看到返回结果,但是在非交互式使用场景(比如作为模块运行)时,如果没有收集返回值也没有类似打印输出的情况下,一切看似正常,但实际没有运行的情况,将造成难以调试的bug。

## 解决不同

如何才能让python3的map函数的行为和python2的一样呢?
答案是使用list函数,将上述代码稍作改动:

<pre>`list(map(task, range(4)))
`</pre>

那么你将得到输出:

<pre>`    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_unorderedmap方法,实际上python2和python3差异还是比较大的,所以如果遇到兼容性问题,第一件事情就是立即查阅官方文档。