2

I was doing a couple of tests, and found that xrange() is MUCH faster than range() (as confirmed by various questions/answers as well):

>>> from timeit import timeit
>>> timeit(stmt = 'x = range(1000)', number = 10000)
0.38216601211680734
>>> timeit(stmt = 'x = xrange(1000)', number = 10000)
0.010537726631953959 # xrange is much faster than range

I got curious, so I tried another test, to see if list(xrange(1000)) would still be faster than simply range(1000):

>>> timeit(stmt = 'x = range(1000)', number = 10000)
0.3858838963796529
>>> timeit(stmt = 'x = list(xrange(1000))', number = 10000)
0.492734766028903 # now, xrange is slower

This is also true for more calls:

>>> timeit(stmt = 'x = range(1000)', number = 100000)
3.6457308233315757
>>> timeit(stmt = 'x = list(xrange(1000))', number = 100000)
5.722031755612818

So, my question is, why is list(xrange) significantly slower than range itself?

I saw this question on the slowness of list(), dict(), and other constructor methods, so is that why list(xrange) is so much slower?

Using dis.dis(), I found that list(xrange) performs more computations than range):

>>> dis.dis('x = list(xrange(1000))')
          0 SETUP_LOOP      15648 (to 15651)
          3 SLICE+2        
          4 IMPORT_NAME     29545 (29545)
          7 LOAD_GLOBAL     30760 (30760)
         10 POP_JUMP_IF_FALSE 28257
         13 BUILD_LIST      10341
         16 <49>           
         17 <48>           
         18 <48>           
         19 <48>           
         20 STORE_SLICE+1  
         21 STORE_SLICE+1  
>>> dis.dis('x = range(1000)')
          0 SETUP_LOOP      15648 (to 15651)
          3 SLICE+2        
          4 POP_JUMP_IF_FALSE 28257
          7 BUILD_LIST      10341
         10 <49>           
         11 <48>           
         12 <48>           
         13 <48>           
         14 STORE_SLICE+1  
Community
  • 1
  • 1
Rushy Panchal
  • 16,979
  • 16
  • 61
  • 94
  • What is the difference between range and xrange - http://stackoverflow.com/questions/94935/what-is-the-difference-between-range-and-xrange – ndpu Apr 27 '13 at 13:26
  • @ndpu I know the difference between the two. I am wondering why `list(xrange)` is slower than `range` itself. – Rushy Panchal Apr 27 '13 at 13:27
  • `xrange(1000)` doesn't create a list at all. It's a generator. It's closer to assigning a constant than creation of a list, in terms of performance. – Stjepan Bakrac Apr 27 '13 at 13:27
  • @StjepanBakrac What's your point? OP knows that, and it's not in any way related to the question. –  Apr 27 '13 at 13:31
  • @delnan If that was the case, why does he compare them and sound surprised about it? Saying that xrange() is MUCH [sic] faster than range() is a pointless statement, because they do entirely different things. Also, if he knew it, the answer to the question would be self-evident, because it's simply more overhead to achieve the same thing. It was not intended as a response to his actual question, which is why I didn't post it as an answer, but I thought it might help the confusion of the two terms. – Stjepan Bakrac Apr 27 '13 at 13:39
  • @StjepanBakrac The comparison is between `list(xrange(n))` and `range(n)`, not between `xrange(n)` and `range(n)` ;-) But I see your point. –  Apr 27 '13 at 13:49

2 Answers2

6

Of course range() is going to be faster, when the end product you desire is a list of all numbers in a range, range does all of that in a single function call. As opposed to list(xrange()) which burdens the list(..) constructor with the overhead of the rangeiterator object created to iterate over the xrange object, which the list(..) constructor must consume. Whereas range() constructs the list immediately, no intermediate iterator consumption... how could that be beaten? The main difference is: 1 function call vs 2 and less importantly 1 global lookup vs 2.

jamylak
  • 128,818
  • 30
  • 231
  • 230
2

range() will construct a list right away and return it to you. So if it has many items it is slow to build.

On the other hand, xrange() returns directly an iterator-like object which yields values when you ask for them. From the docs:

xrange(start, stop[, step])
This function is very similar to range(), but returns an xrange object instead of a list. This is an opaque sequence type which yields the same values as the corresponding list, without actually storing them all simultaneously. The advantage of xrange() over range() is minimal (since xrange() still has to create the values when asked for them) except when a very large range is used on a memory-starved machine or when all of the range’s elements are never used (such as when the loop is usually terminated with break).

So, in your first example, xrange() is naturally faster, while in the second one it's slower because, while range() already returns a list (which won't be converted then), list(xrange()) will have to do more work to not only produce values, but also creating a new list and storing values in.

P.S. This holds true for Python 2. In Python 3, instead, there is only range() which works exactly like the Python 2-xrange().

rubik
  • 8,814
  • 9
  • 58
  • 88
  • @Blender: Yes added. Thanks. However the OP does not seem to have clear the base difference between `range()` and `xrange()` (just look at the first sentence) so I thought I was going to clarify it. – rubik Apr 27 '13 at 13:30
  • 1
    I knew the difference prior to asking this question. – Rushy Panchal Apr 27 '13 at 13:35