鉴于以下测试:
>>> 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
使用Python 3显着改善了地图,列表理解受到了严重影响。
问题:将代码从Python 2移植到Python 3时,是否建议将列表推导更改为map()?
答案 0 :(得分:6)
您没有正确测试。在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上放慢列表理解速度的原因是因为它们有自己的适当范围,就像生成器表达式和dict以及集合理解在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代码。