Python's range() vs xrange() Functions

Both range() and xrange() are intrinsic functions in Python, serving the purpose of generating integers within specified ranges. The deliberation regarding the comparison between range() and xrange() gains significance primarily when operating within the dual context of Python 2.x and Python 3. This distinction arises due to the fact that the range() function in Python 3.x essentially serves as a reimagination of the xrange() function in Python 2.x, operating in the same manner as its predecessor.

In Python 2.x:

  1. range() creates a list, so if you do range(1, 10000000) it creates a list in memory with 9999999 elements. This will become an expensive operation on very large ranges.

  2. xrange() is a sequence object that evaluates lazily. It is much more optimised, it will only compute the next value when needed (via an xrange sequence object) and does not create a list of all values like range() does.

In Python 3:

  1. range() does the equivalent of python's xrange(), and to get the list. If you need to actually generate the list, you will need to do:

In python 3, range() does what xrange() used to do and xrange() does not exist. If you want to write code that will run on both Python 2 and Python 3, you can't use xrange().


  1. range()

The range() type boasts a performance advantage when iterating over the same sequence repeatedly, owing to its utilization of genuine integer objects. Conversely, the xrange() type necessitates the recreation of integer objects for each iteration, thereby resulting in comparatively slower performance. However, it's imperative to note that range() may incur higher memory consumption. Additionally, xrange() exhibits limitations in scenarios requiring a true list structure, such as the absence of support for slices or list methods, further restricting its usability.

  1. xrange()

The merit of the xrange() type resides in its consistent memory consumption, as an xrange() object maintains a uniform memory footprint regardless of the range's magnitude. Functioning as an opaque sequence, it offers identical values as a corresponding list without the need to store them all concurrently. Particularly when dealing with expansive ranges, the use of xrange() is often recommended for enhanced performance during iteration.

Syntax of range and xrange:

range(start, stop, step)
xrange(start, stop, step)

Return type:

  1. range() – This returns a list of numbers created using range() function.

  2. xrange() – This function returns the generator object that can be used to display numbers only by looping. Only particular range is displayed on demand and hence called lazy evaluation .

Deprecation of xrange()

In Python 3.x, the xrange() function does not exist anymore. The range() function now does what xrange() does in Python 2.x, so to keep your code portable, you might want to stick to using range() instead. Of course, you could always use the 2to3 tool that Python provides in order to convert your code, but that introduces more complexity.

range() vs xrange() in Python

NameError: name 'xrange' is not defined

The error message "'xrange' is not defined" signifies an attempt to execute Python 2 code within a Python 3 environment. In Python 2, iterable objects are often generated using the xrange() function, frequently employed within "for loops," demonstrating similarities to generators. However, in Python 3, the range() function is a direct equivalent to the xrange() method, rendering the latter obsolete. As a result, any usage of xrange() in Python 3 will trigger a "NameError: name 'xrange' is not defined" error.


Python offers both the range() and xrange() functions for generating sequences of integers. While range() constructs a list of integers in memory, xrange() generates an iterator, conserving memory, making it advantageous for large ranges. However, in Python 3, xrange() is replaced by range(), rendering the latter more versatile across both versions.