What is the difference between range and xrange functions in Python 2.X?
Solution 1
In Python 2.x:
range
creates a list, so if you dorange(1, 10000000)
it creates a list in memory with9999999
elements.xrange
is a sequence object that evaluates lazily.
In Python 3:
range
does the equivalent of Python 2'sxrange
. To get the list, you have to explicitly uselist(range(...))
.xrange
no longer exists.
Solution 2
range creates a list, so if you do
range(1, 10000000)
it creates a list in memory with9999999
elements.
xrange
is a generator, so itis a sequence objectis athat evaluates lazily.
This is true, but in Python 3, range()
will be implemented by the Python 2 xrange()
. If you need to actually generate the list, you will need to do:
list(range(1,100))
Solution 3
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.
Solution 4
xrange
only stores the range params and generates the numbers on demand. However the C implementation of Python currently restricts its args to C longs:
xrange(2**32-1, 2**32+1) # When long is 32 bits, OverflowError: Python int too large to convert to C long
range(2**32-1, 2**32+1) # OK --> [4294967295L, 4294967296L]
Note that in Python 3.0 there is only range
and it behaves like the 2.x xrange
but without the limitations on minimum and maximum end points.
Solution 5
xrange returns an iterator and only keeps one number in memory at a time. range keeps the entire list of numbers in memory.
Teifion
I am a Software Engineer in a UK Car Insurance provider. I mainly work in Python and PHP.
Updated on May 18, 2021Comments
-
Teifion about 3 years
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
for i in range(0, 20): for i in xrange(0, 20):
-
Teifion over 15 yearsThe library is good but it's not always so easy to get the answer to the question you have.
-
Simon Dugré over 15 yearsGo to the library reference, hit ctrl+f, search for range and you will get two results. It's not much effort to find the answer to this question.
-
Benjamin Autin over 15 yearsI don't see that being a huge problem (regarding breaking existing applications) as range was mostly for generating indexes to be used in for loops as "for i in range(1, 10):"
-
Cervo about 12 years+1 Thanks for this answer, the information about Python 3 replacing range with xrange is very useful. I actually told someone to use xrange instead or range and they said that it did not matter in python 3, so I google searched for more information and this answer came up :)
-
stalk almost 12 years+1 for timeit example. Note: to run in windows cmd it is needed to use double quote, i.e. ". So code will be
python -m timeit "for i in xrange(1000000):" " pass"
-
Vajk Hermecz over 11 yearsRunning a benchmark like this, one time, doesnt provide exact timing results. There is always a variance.. It could be either GC, or another process stealing the CPU... anything. That's why benchmarks are usually run 10-100-1000-...
-
Dave Everitt over 11 yearsthis is just a hasty snippet printout - I ran it a few times, but only up to around 100, and
xrange
seemed slightly quicker, although with Python 3 the comparison is now redundant. -
endolith almost 10 yearsThe main benefit of xrange is memory, not time.
-
Bob Stein almost 10 years+1 for the practical answer: use range unless huge. BTW they are conceptually identical, correct? Oddly no answer spells that out.
-
João dos Reis over 9 yearsWhy did they make xrange, rather than making range lazy?
-
Austin Mohr over 9 yearsIf xrange is faster and doesn't hog memory, why ever use range?
-
chacham15 over 9 yearsI agree with your statement generally, but your evaluation is wrong:
the extra overhead is only 0.04 seconds
isnt the correct way to look at it,(90.5-51.1)/51.1 = 1.771 times slower
is correct because it conveys that if this is the core loop of your program it can potentially bottleneck it. However, if this is a small part then 1.77x isnt much. -
Alvaro about 9 years@RobertGrant If you iterate over that list 1000 times, it'll be slower to generate the values each time
-
abarnert about 9 years
xrange
does not return an iterator. -
abarnert about 9 years
xrange
does not return a generator object. -
abarnert about 9 yearsI realize this is 5 years old, but that post is wrong about nearly everything.
xrange
is not an iterator. The list returned byrange
does support iteration (a list is pretty much the prototypical example of an iterable). The overall benefit ofxrange
is not "minimal". And so on. -
abarnert about 9 yearsThis is what
timeit
is for. It takes care of running many times, disabling GC, using the best clock instead oftime
, etc. -
kmario23 about 9 yearsIf I understand correctly, that is how it is explained here(for Python 2.x): wiki.python.org/moin/Generators
-
abarnert about 9 yearsThen the wiki is wrong. (I don't know who the "SH" is who added and signed that comment.) The official documentation is right; you can test it yourself and see whether it's a generator or a sequence.
-
kmario23 about 9 yearsok. But it's still confusing after reading this: stackoverflow.com/questions/135041/…
-
abarnert about 9 yearsIf you read even just the first sentence of that comment, it says "
xrange(1000)
is an object that acts like a generator (although it certainly is not one)." (emphasis mine) But even if it didn't say that, are you going to trust a throwaway comment by a random SO user over the official Python documentation, or over what you can see by testing it yourself? -
abarnert about 9 yearsAt any rate, it really doesn't act like a generator at all. A sequence is a thing that can be iterated repeatedly, because its
__iter__
returns a new object, and it can be indexed, because it has a__getitem__
, and so on. A generator is a thing that's consumed as its iterated, because its__iter__
returns self, and it can't be indexed, and it contains a suspended stack frame, and it hassend
andthrow
methods. Which one of those doesxrange
sound like? -
abarnert about 9 yearsThe fun question is what to do when the interpreter disagrees with the official docs, or with a different interpreter… But fortunately, that doesn't come up too often…
-
Paul Draper about 9 years@RobertGrant, they did. In Python 3. (They couldn't do that in the Python 2.x line, since all changes must be backwards compatible.)
-
abarnert almost 9 years
xrange
does not create an iterator instance. It creates anxrange
object, which is iterable, but not an iterator—almost (but not quite) a sequence, like a list. -
ratulotron almost 9 yearsCan someone explain what "evaluates lazily" means? Thanks!
-
Onilol over 8 years@Ratul it means that each
i
is evaluated on demand rather than on initialization. -
th3an0maly about 8 years
xrange()
isn't a generator.xrange(n)
.__iter__()` is. -
Darshan Chaudhary about 8 years
xrange
is an iterator that evaluates lazily? Calling theiter()
method on xrange returns a generator? -
TM. about 8 yearsThis is bad advice. Really the only upside to
range
is if you have some aesthetic opinion on it being less ugly to read thanxrange
, or if you actually need alist
. Additionally, running timeit on your machine is likely not going to resemble the environments in which your code is going to be running, and does nothing to tell you about the memory implications. -
SIslam over 7 years
and only keeps one number in memory at a time
and where the rest are placed please guide me.. -
Justin Meiners over 7 years@SIslam If it knows the start, end, and current, it can compute the next, one at a time.
-
Sandeep almost 6 yearsThe library reference is not working. Can you please update it?
-
winterlight about 5 yearsWhat is wrong with calling
xrange
a generator? It is a function containingyield
statement, and according to glossary such functions are called generators. -
McSinyx about 4 years@winterlight, think the correct term for it is iterator. Generators should be able to receive as well.
-
scign almost 4 years@McSinyx - winterlight is correct that a function that returns a generator is also referred to as a generator. A generator object is a special case of iterator. See generators vs iterators.
-
McSinyx almost 4 years@scign, see PEP 342 for the canonical definition of the generator protocol. A nice sum up can be found in type annotation documentation (these are aliased as
typing.*
). -
scign almost 4 years@McSinyx glad you agree.
-
McSinyx almost 4 yearsNo I don't, @scign. Have you read the linked PEP and doc? In the past the two terms might have been used interchangeably, but at the time of writing, generators must be able to receive values. In addition, Python 3 range is not an iterator either (try
next(range(42))
). -
ShadowRanger over 3 years@DarshanChaudhary:
xrange
is an iterable (with sequence-like behaviors) that evaluates lazily, not an iterator. Callingiter()
on it creates an iterator (which people loosely call a generator, though in Python, "generator" is a specific type of iterator made with a generator expression or a function using theyield
keyword, neither of which actually applies toxrange
). -
Daniel almost 2 yearsTo use xrange in py3 and have py2 backwards compatibility use:
from past.builtins import xrange