给出以下测试:
>>> 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 代码。
