为什么Python的枚举速度如此之慢?

Myk*_*hko 6 python

为什么"枚举"比"xrange + lst [i]"慢?


>>> from timeit import Timer
>>> lst = [1,2,3,0,1,2]*1000
>>> setup = 'from __main__ import lst'
>>> s1 = """
for i in range(len(lst)):
    elem = lst[i]
"""
>>> s2 = """
for i in xrange(len(lst)):
    elem = lst[i]
"""
>>> s3 = """
for i, v in enumerate(lst):
    elem = v
"""
>>> t1 = Timer(s1, setup); t2 = Timer(s2, setup); t3 = Timer(s3, setup)
>>> t1.timeit(3000), t2.timeit(3000), t3.timeit(3000)
(1.9263118636586494, 1.6119261665937992, 1.9606022553145719)
>>> t1.timeit(3000), t2.timeit(3000), t3.timeit(3000)
(1.93520258859715, 1.6145745478824836, 1.9529405971988041)

编辑:我记得为什么

for i, v in enumerate(lst):
    elem = i, v
Run Code Online (Sandbox Code Playgroud) 慢于
for i in xrange(len(lst)):
    elem = i, lst[i]
Run Code Online (Sandbox Code Playgroud)

Ale*_*lli 15

如果你正确测量,你会发现基本上没有区别(在这个例子中,枚举在微观上比xrange快,但在噪声范围内):

$ python -mtimeit -s'lst=[1,2,3,0,1,2]*1000' 'for i in xrange(len(lst)): elem=lst[i]'
1000 loops, best of 3: 480 usec per loop
$ python -mtimeit -s'lst=[1,2,3,0,1,2]*1000' 'for i, elem in enumerate(lst): pass'
1000 loops, best of 3: 473 usec per loop
Run Code Online (Sandbox Code Playgroud)

(顺便说一句,我总是建议timeit在这样的shell提示符下使用,不要在代码内或在解释器提示符下使用,因为输出的格式和可用性非常好,具有时间和所有内容的度量单位).

在您的代码中,您在枚举的情况下有一个额外的赋值:在forheader子句中将列表项分配给v ,然后再分配velem; 而在xrange情况下,您只需将项目分配一次elem.在我的情况下,我当然也只分配一次,当然; 你为什么要分配多次?!无论你在做什么elemi在循环体中做什么,你都可以用我正在测量的两种形式完全相同,只是没有你的枚举案例所具有的冗余.


Joh*_*hin 5

可能是因为你蹒跚而行enumerate.试试这个:

>>> s3 = """
for i, elem in enumerate(lst):
    pass
"""
Run Code Online (Sandbox Code Playgroud)

更新timeit在亚力克特未提及的shell提示符下使用的两个额外原因:

(1)为你做"N的最佳".
(2)它可以为您提供多少次迭代以获得有意义的结果.

  • @TokenMacGuy和2个评论代码:"已经包含了查找的列表元素......你已经执行了两次查找":这不正确; 该元素仅从列表中提取出来; 两个版本之间的区别是`x = y`形式的冗余分配,它不涉及"查找". (3认同)
  • 如果不清楚为什么John的答案有意义,枚举产生的结果已经包含了查找的列表元素.通过在for循环变量中使用该名称,可以清楚地表达出来.在原始版本中,您已执行两次查找! (2认同)