Apparently xrange is faster but I have no idea why it\'s faster (and no proof besides the anecdotal so far that it is faster) or what besides that is different about
The difference decreases for smaller arguments to range(..)
/ xrange(..)
:
$ python -m timeit "for i in xrange(10111):" " for k in range(100):" " pass"
10 loops, best of 3: 59.4 msec per loop
$ python -m timeit "for i in xrange(10111):" " for k in xrange(100):" " pass"
10 loops, best of 3: 46.9 msec per loop
In this case xrange(100)
is only about 20% more efficient.
Additionally, if do list(xrange(...))
will be equivalent to range(...)
.
So list
is slow.
Also xrange
really doesn't fully finish the sequence
So that's why its not a list, it's a xrange
object
range() in Python 2.x
This function is essentially the old range()
function that was available in Python 2.x
and returns an instance of a list
object that contains the elements in the specified range.
However, this implementation is too inefficient when it comes to initialise a list with a range of numbers. For example, for i in range(1000000)
would be a very expensive command to execute, both in terms of memory and time usage as it requires the storage of this list into the memory.
range() in Python 3.x
and xrange() in Python 2.x
Python 3.x
introduced a newer implementation of range()
(while the newer implementation was already available in Python 2.x
through the xrange()
function).
The range()
exploits a strategy known as lazy evaluation. Instead of creating a huge list of elements in range, the newer implementation introduces the class range
, a lightweight object that represents the required elements in the given range, without storing them explicitly in memory (this might sound like generators but the concept of lazy evaluation is different).
As an example, consider the following:
# Python 2.x
>>> a = range(10)
>>> type(a)
<type 'list'>
>>> b = xrange(10)
>>> type(b)
<type 'xrange'>
and
# Python 3.x
>>> a = range(10)
>>> type(a)
<class 'range'>
Some of the other answers mention that Python 3 eliminated 2.x's range
and renamed 2.x's xrange
to range
. However, unless you're using 3.0 or 3.1 (which nobody should be), it's actually a somewhat different type.
As the 3.1 docs say:
Range objects have very little behavior: they only support indexing, iteration, and the
len
function.
However, in 3.2+, range
is a full sequence—it supports extended slices, and all of the methods of collections.abc.Sequence with the same semantics as a list
.*
And, at least in CPython and PyPy (the only two 3.2+ implementations that currently exist), it also has constant-time implementations of the index
and count
methods and the in
operator (as long as you only pass it integers). This means writing 123456 in r
is reasonable in 3.2+, while in 2.7 or 3.1 it would be a horrible idea.
* The fact that issubclass(xrange, collections.Sequence)
returns True
in 2.6-2.7 and 3.0-3.1 is a bug that was fixed in 3.2 and not backported.
xrange uses an iterator (generates values on the fly), range returns a list.
Remember, use the timeit
module to test which of small snippets of code is faster!
$ python -m timeit 'for i in range(1000000):' ' pass'
10 loops, best of 3: 90.5 msec per loop
$ python -m timeit 'for i in xrange(1000000):' ' pass'
10 loops, best of 3: 51.1 msec per loop
Personally, I always use range()
, unless I were dealing with really huge lists -- as you can see, time-wise, for a list of a million entries, the extra overhead is only 0.04 seconds. And as Corey points out, in Python 3.0 xrange()
will go away and range()
will give you nice iterator behavior anyway.