What is the difference between range and xrange functions in Python 2.X?
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.
Python 3 range Vs Python 2 range
Python 3 uses iterators for a lot of things where python 2 used lists.The docs give a detailed explanation including the change to range
.
The advantage is that Python 3 doesn't need to allocate the memory if you're using a large range iterator or mapping.
For example
for i in range(1000000000): print(i)
requires a lot less memory in python 3.
If you do happen to want Python to expand out the list all at once you can
list_of_range = list(range(10))
Should you always favor xrange() over range()?
For performance, especially when you're iterating over a large range, xrange()
is usually better. However, there are still a few cases why you might prefer range()
:
In python 3,
range()
does whatxrange()
used to do andxrange()
does not exist. If you want to write code that will run on both Python 2 and Python 3, you can't usexrange()
.range()
can actually be faster in some cases - eg. if iterating over the same sequence multiple times.xrange()
has to reconstruct the integer object every time, butrange()
will have real integer objects. (It will always perform worse in terms of memory however)xrange()
isn't usable in all cases where a real list is needed. For instance, it doesn't support slices, or any list methods.
[Edit] There are a couple of posts mentioning how range()
will be upgraded by the 2to3 tool. For the record, here's the output of running the tool on some sample usages of range()
and xrange()
RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: ws_comma
--- range_test.py (original)
+++ range_test.py (refactored)
@@ -1,7 +1,7 @@
for x in range(20):
- a=range(20)
+ a=list(range(20))
b=list(range(20))
c=[x for x in range(20)]
d=(x for x in range(20))
- e=xrange(20)
+ e=range(20)
As you can see, when used in a for loop or comprehension, or where already wrapped with list(), range is left unchanged.
Difference between Python xrange and generators?
Both range
and generator
objects are examples of iterable objects.
A range
is defined by a stopping value, with an optional starting value and optional step size allowed. The result is an iterable of integers. A range
also supports operations (like containment) that are not necessarily supported by other iterables.
A generator
is defined by a generator expression or a generator function, either of which results in an iterable of arbitrary values.
The iterable aspect of a range
object can be simulated by a generator
:
def myrange(stop, start=None, step=None):
if start is not None:
from_ = stop
to_ = start
else:
from_ = 0
to_ = stop
if step is None:
step = 1 if from_ < to_ else -1
while from_ < to_:
yield from_
from_ += step
Then
>>> list(myrange(1, 10))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(1, 10))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
As Python 2 reached end-of-life nearly a year ago, there's not much reason to go into range
. Suffice it to say, in Python 2 range
was a function that returned a list of integers, while xrange
was a type whose value represents a list of integers. Python 3 did away with the function and reused the name for the type.
What is the difference between range and xrange functions in Python 2.X?
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.
How is irange() any different from range() or xrange()?
irange()
returns a generator type, which can only be iterated over. Nothing else. Once you iterated over it, the generator is exhausted and can not be iterated over again.
The Python 2 xrange()
type and Python 3 range()
type are sequence types, they support various operations that other sequences support as well, such as reporting on their length, test for containment, and indexing:
>>> xr = xrange(10, 20, 3)
>>> len(xr)
4
>>> 10 in xr
True
>>> xr[0]
10
>>> xr[1]
13
You can iterate over these objects more than once:
>>> for i in xr:
... print i,
...
10 13 16 19
>>> for i in xr:
... print i,
...
10 13 16 19
You can even use the reversed()
function to iterate over them in reverse, efficiently:
>>> for i in reversed(xr):
... print i,
...
19 16 13 10
The Python 3 range()
type is an improved version of xrange()
, in that it supports more sequence operations, is more efficient still, and can handle values beyond sys.maxint
(what would be a long
integer in Python 2).
It supports slicing, for example, which results in a new range()
object for the sliced values:
>>> r = range(10, 20, 3)
>>> r[:2]
range(10, 16, 3)
You can use negative indices just like you can with other Python sequences, to get elements counting from the end:
>>> r[-2]
16
>>> r[-2:]
range(16, 22, 3)
and the type supports testing for equality; two range()
instances are equal if they'd yield the same values:
>>> range(10, 20, 3) == range(10, 21, 3)
True
In Python 2, the only advantage the generator irange()
might have is that it doesn't suffer from the limitation to non-long integers that xrange()
is subjected to:
>>> import sys
>>> xrange(sys.maxint)
xrange(9223372036854775807)
>>> xrange(sys.maxint + 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: Python int too large to convert to C long
range and xrange for 13-digit numbers in Python?
You could try this. Same semantics as range:
import operator
def lrange(num1, num2 = None, step = 1):
op = operator.__lt__
if num2 is None:
num1, num2 = 0, num1
if num2 < num1:
if step > 0:
num1 = num2
op = operator.__gt__
elif step < 0:
num1 = num2
while op(num1, num2):
yield num1
num1 += step
>>> list(lrange(138264128374162347812634134, 138264128374162347812634140))
[138264128374162347812634134L, 138264128374162347812634135L, 138264128374162347812634136L, 138264128374162347812634137L, 138264128374162347812634138L, 138264128374162347812634139L]
Another solution would be using itertools.islice
, as suggested inxrange
's documentation
Related Topics
Word Boundary With Words Starting or Ending With Special Characters Gives Unexpected Results
Equivalent of Shell 'Cd' Command to Change the Working Directory
Changing One Character in a String
Difference Between Map, Applymap and Apply Methods in Pandas
Typeerror: Method() Takes 1 Positional Argument But 2 Were Given
What Does the "At" (@) Symbol Do in Python
Pip Install from Git Repo Branch
Python Function Global Variables
How Are Python'S Built in Dictionaries Implemented
Count the Frequency That a Value Occurs in a Dataframe Column
How to Call a Function from Another .Py File
How to List All Functions in a Module
Sorting Arrays in Numpy by Column
Sort a List of Tuples by 2Nd Item (Integer Value)
How to Use Pickle to Save a Dict (Or Any Other Python Object)