Python 2 vs 3:用map()替换列表推导?

1 python performance list-comprehension python-3.x map-function

鉴于以下测试:

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

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

Python27 Python34
1.3s     0.5s      map()
0.6s     0.9s      list comprehension
Run Code Online (Sandbox Code Playgroud)

使用Python 3显着改善了地图,列表理解受到严重影响.

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

Mar*_*ers 6

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

您需要包含迭代以查看哪种方法更快; 你可以使用collections.deque()长度为0,这将迭代而不产生新的列表对象:

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')
Run Code Online (Sandbox Code Playgroud)

通过应用这deque()两个你甚至再次得分.

现在列表推导在两个平台上获胜:

Python27 Python34
1.91s     2.00s      map()
1.18s     1.85s      list comprehension
Run Code Online (Sandbox Code Playgroud)

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

列表理解在Python 3上放慢速度的原因是因为它们有自己的适当范围,就像生成器表达式以及dict和set comprehensions在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
Run Code Online (Sandbox Code Playgroud)

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