Search code examples
pythonrangegeneratorxrange

How is irange() any different from range() or xrange()?


I was going through Python Generators Wiki when I came across this RangeGenerator page which talks about irange() -

This will let us iterator over large spans of numbers without resorting to xrange, which is a lazy list as opposed to a generator.

I can't seem to understand the test suite and the implementation described on that page. I know that range() creates a list in the memory (from Python 2.7 point of view) and xrange() is a generator. How is irange() any different?


Solution

  • 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