Skip to main content
 首页 » 编程设计

python 2 与 3 : Replace list comprehensions with map()

2025年05月04日25qq号

给出以下测试:

>>> import timeit 
>>> timeit.timeit("[x + 'abc' for x in ['x', 'y', 'z']]") 
>>> timeit.timeit("map(lambda x: x + 'abc', ['x', 'y', 'z'])") 

使用 Python 2.7 和 3.4 (Debian 8/testing/jessie) 我得到以下数字:

Python27 Python34 
1.3s     0.5s      map() 
0.6s     0.9s      list comprehension 

map 在 Python 3 中得到显着改进,列表理解受到严重影响。

问题:将代码从 Python 2 移植到 Python 3 时,是否建议将列表理解更改为 map()?

请您参考如下方法:

您没有正确测试。在 Python 3 中,map() 返回一个迭代器,而不是一个列表。您实际上并没有在测试中进行迭代,只是测试迭代器的创建。

您需要包括迭代 以查看哪种方法更快;您可以使用长度为 0 的 collections.deque(),这将在不生成新列表对象的情况下进行迭代:

import timeit 
timeit.timeit("deque([x + 'abc' for x in ['x', 'y', 'z']], maxlen=0)", 
              'from collections import deque') 
timeit.timeit("deque(map(lambda x: x + 'abc', ['x', 'y', 'z']), maxlen=0)", 
              'from collections import deque') 

通过将 deque() 应用于两者,您可以再次平衡分数。

现在列表理解在两个平台上都获胜:

Python27 Python34 
1.91s     2.00s      map() 
1.18s     1.85s      list comprehension 

您真的应该使用更大的输入列表来正确测试差异;太多了

列表理解在 Python 3 上变慢的原因是因为它们有自己的适当范围,就像生成器表达式和字典以及集合理解在 Python 2 和 3 上一样。

如果您的 map 函数完全用 C 实现(而不是 lambda,后者返回 Python,map() 可以获胜:

>>> timeit.timeit("deque([m(i) for i in ['x', 'y', 'z']], maxlen=0)", 
...               "from collections import deque; from operator import methodcaller; m = methodcaller('__add__', 'abc')") 
2.3514049489967874 
>>> timeit.timeit("deque(map(methodcaller('__add__', 'abc'), ['x', 'y', 'z']), maxlen=0)", 
...               'from collections import deque; from operator import methodcaller') 
1.7684289459939464 

这里是 methodcaller() object通过为每个使用的对象调用 str.__add__ 方法,避免回调到 Python 代码。