What is the difference between range and xrange functions in Python 2.X?

后端 未结 28 2039
深忆病人
深忆病人 2020-11-22 03:14

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

相关标签:
28条回答
  • 2020-11-22 03:56

    The difference decreases for smaller arguments to range(..) / xrange(..):

    $ python -m timeit "for i in xrange(10111):" " for k in range(100):" "  pass"
    10 loops, best of 3: 59.4 msec per loop
    
    $ python -m timeit "for i in xrange(10111):" " for k in xrange(100):" "  pass"
    10 loops, best of 3: 46.9 msec per loop
    

    In this case xrange(100) is only about 20% more efficient.

    0 讨论(0)
  • 2020-11-22 03:56

    Additionally, if do list(xrange(...)) will be equivalent to range(...).

    So list is slow.

    Also xrange really doesn't fully finish the sequence

    So that's why its not a list, it's a xrange object

    0 讨论(0)
  • 2020-11-22 03:57

    range() in Python 2.x

    This function is essentially the old range() function that was available in Python 2.x and returns an instance of a list object that contains the elements in the specified range.

    However, this implementation is too inefficient when it comes to initialise a list with a range of numbers. For example, for i in range(1000000) would be a very expensive command to execute, both in terms of memory and time usage as it requires the storage of this list into the memory.


    range() in Python 3.x and xrange() in Python 2.x

    Python 3.x introduced a newer implementation of range() (while the newer implementation was already available in Python 2.x through the xrange() function).

    The range() exploits a strategy known as lazy evaluation. Instead of creating a huge list of elements in range, the newer implementation introduces the class range, a lightweight object that represents the required elements in the given range, without storing them explicitly in memory (this might sound like generators but the concept of lazy evaluation is different).


    As an example, consider the following:

    # Python 2.x
    >>> a = range(10)
    >>> type(a)
    <type 'list'>
    >>> b = xrange(10)
    >>> type(b)
    <type 'xrange'>
    

    and

    # Python 3.x
    >>> a = range(10)
    >>> type(a)
    <class 'range'>
    
    0 讨论(0)
  • 2020-11-22 03:58

    Some of the other answers mention that Python 3 eliminated 2.x's range and renamed 2.x's xrange to range. However, unless you're using 3.0 or 3.1 (which nobody should be), it's actually a somewhat different type.

    As the 3.1 docs say:

    Range objects have very little behavior: they only support indexing, iteration, and the len function.

    However, in 3.2+, range is a full sequence—it supports extended slices, and all of the methods of collections.abc.Sequence with the same semantics as a list.*

    And, at least in CPython and PyPy (the only two 3.2+ implementations that currently exist), it also has constant-time implementations of the index and count methods and the in operator (as long as you only pass it integers). This means writing 123456 in r is reasonable in 3.2+, while in 2.7 or 3.1 it would be a horrible idea.


    * The fact that issubclass(xrange, collections.Sequence) returns True in 2.6-2.7 and 3.0-3.1 is a bug that was fixed in 3.2 and not backported.

    0 讨论(0)
  • 2020-11-22 03:59

    xrange uses an iterator (generates values on the fly), range returns a list.

    0 讨论(0)
  • 2020-11-22 04:01

    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.

    0 讨论(0)
提交回复
热议问题