Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Python's enumerate so slow?

Tags:

python

Why is "enumerate" slower than "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)

EDIT: I keep in mind why

for i, v in enumerate(lst):
    elem = i, v
slower than
for i in xrange(len(lst)):
    elem = i, lst[i]
like image 736
Mykola Kharechko Avatar asked Aug 29 '09 21:08

Mykola Kharechko


2 Answers

If you measure properly you'll see there's essentially no difference (enumerate is microscopically faster than xrange in this example, but well within noise):

$ 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

(BTW, I always recommend using timeit at the shell prompt like this, not within code or at the interpreter prompt as you're doing, just because the output is so nicely formatted and usable, with units of measure of time and everything).

In your code, you have an extra assignment in the enumerate case: you assign the list item to v in the for header clause, then again assign v to elem; while in the xrange case you only assign the item once, to elem. In my case I'm also assigning only once in either case, of course; why would you WANT to assign multiple times anyway?! Whatever you're doing with elem and i in the body of the loop you can do it identically in the two forms I'm measuring, just without the redundancy that your enumerate case has.

like image 65
Alex Martelli Avatar answered Oct 16 '22 08:10

Alex Martelli


Possibly because you have hobbled enumerate. Try this:

>>> s3 = """
for i, elem in enumerate(lst):
    pass
"""

Update Two extra reasons for using timeit at the shell prompt that Alex didn't mention:

(1) It does "best of N" for you.
(2) It works out for you how many iterations are necessary to get a meaningful result.

like image 39
John Machin Avatar answered Oct 16 '22 08:10

John Machin