Python:列表理解与映射
关于这个问题,有人能解释为什么当列表理解不调用函数时,列表理解会比Python:列表理解与映射,python,performance,Python,Performance,关于这个问题,有人能解释为什么当列表理解不调用函数时,列表理解会比map产生更好的结果,即使map中没有lambda函数,但调用函数时会产生最差的结果 import timeit print timeit.Timer('''[i**2 for i in xrange(100)]''').timeit(number = 100000) print timeit.Timer('''map(lambda i: i**2, xrange(100))''').timeit(number = 10000
map
产生更好的结果,即使map
中没有lambda函数,但调用函数时会产生最差的结果
import timeit
print timeit.Timer('''[i**2 for i in xrange(100)]''').timeit(number = 100000)
print timeit.Timer('''map(lambda i: i**2, xrange(100))''').timeit(number = 100000)
print timeit.Timer(setup="""def my_pow(i):
return i**2
""",stmt="""map(my_pow, xrange(100))""").timeit(number = 100000)
print timeit.Timer(setup="""def my_pow(i):
return i**2
""",stmt='''[my_pow(i) for i in xrange(100)]''').timeit(number = 100000)
结果:
1.03697046805 <-- list comprehension without function call
1.96599485313 <-- map with lambda function
1.92951520483 <-- map with function call
2.23419570042 <-- list comprehension with function call
1.03697046805所有计时结果都可以用以下事实来解释:
CPython有相当高的函数调用开销
map(f,it)
略快于[f(x)for x in it]
代码的第一个版本根本没有定义函数,因此没有函数调用开销。第二个版本需要定义一个函数,因此在每次迭代中都有函数调用开销。第三个版本与第二个版本完全相同–函数和lambda表达式是相同的。根据事实2,最后一个版本更慢。无论在map
中调用的函数是lambda函数还是常规函数,开销仍然存在。不知道为什么一个函数调用的列表理解会比map()
慢。@millimoose但是lambda函数会为每个itetaration声明,这会有任何变化吗?@zenpoy:函数调用参数会在调用函数之前计算,因此函数只声明一次。无法删除对我phine的注释:(@SvenMarnach我想他/她说的是my_pow
定义在整个执行过程中只解释一次(在设置中)每个迭代都定义了lambda。这是一个有效的问题,lambda可能导致它的版本稍微慢一些。我可以想到两个可能的原因(2):map
的循环直接在C中进行,因此循环中的开销稍微小一些,对于map
而言,对名称f
的引用只需要解决一次,但是对于列表理解,每次迭代都需要解决一次。第二次对我来说更重要,但是有没有办法告诉我哪一次贡献更大?@Dougal:这是n这是第一次有人提到C中的循环,但我从未找到一个引用或其他东西来替代它应该更快。@RikPoggi我试着检查Python源代码,3.x中的map
实际上返回了一个迭代器,并继续使用参数的迭代器,这使得这一理论不太可能所有这些都是基于C的,可能会节省一些成本,但C中没有神秘的“循环”。在这方面比较2.x和3.x的性能可能会很有趣(如果不是决定性的话)。@millimoose:类似“循环完全是在C中完成的”之类的事情通常意味着执行循环不需要Python字节码求值。@SvenMarnach很公平,但是这种区别会有显著的区别吗?运行时仍然需要处理所有操作解释器状态的开销;在我看来,字节码分派本身并不是主要的贡献者经济放缓。