Python Language Differences between range and xrange functions


Example

In Python 2, range function returns a list while xrange creates a special xrange object, which is an immutable sequence, which unlike other built-in sequence types, doesn't support slicing and has neither index nor count methods:

Python 2.x2.3
print(range(1, 10))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]

print(isinstance(range(1, 10), list))
# Out: True

print(xrange(1, 10))
# Out: xrange(1, 10)

print(isinstance(xrange(1, 10), xrange))
# Out: True

In Python 3, xrange was expanded to the range sequence, which thus now creates a range object. There is no xrange type:

Python 3.x3.0
print(range(1, 10))
# Out: range(1, 10)

print(isinstance(range(1, 10), range))
# Out: True

# print(xrange(1, 10))
# The output will be:
#Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
#NameError: name 'xrange' is not defined

Additionally, since Python 3.2, range also supports slicing, index and count:

print(range(1, 10)[3:7])
# Out: range(3, 7)
print(range(1, 10).count(5))
# Out: 1
print(range(1, 10).index(7))
# Out: 6

The advantage of using a special sequence type instead of a list is that the interpreter does not have to allocate memory for a list and populate it:

Python 2.x2.3
# range(10000000000000000)
# The output would be:
# Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
# MemoryError

print(xrange(100000000000000000))
# Out: xrange(100000000000000000)

Since the latter behaviour is generally desired, the former was removed in Python 3. If you still want to have a list in Python 3, you can simply use the list() constructor on a range object:

Python 3.x3.0
print(list(range(1, 10)))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]

Compatibility

In order to maintain compatibility between both Python 2.x and Python 3.x versions, you can use the builtins module from the external package future to achieve both forward-compatiblity and backward-compatiblity:

Python 2.x2.0
#forward-compatible
from builtins import range

for i in range(10**8):
    pass
Python 3.x3.0
#backward-compatible
from past.builtins import xrange

for i in xrange(10**8):
    pass

The range in future library supports slicing, index and count in all Python versions, just like the built-in method on Python 3.2+.