关于循环:在python 2.x中,range和xrange函数有什么区别?

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

显然xrange更快,但我不知道为什么它更快(除了目前为止的轶事,没有证据证明它更快),或者除此之外还有什么不同的地方

1
2
for i in range(0, 20):
for i in xrange(0, 20):

range创建一个列表,所以如果您执行range(1, 10000000)操作,它会在内存中创建一个包含9999999元素的列表。

xrange是一个顺序对象,它的计算比较缓慢。

应该从@thiago的提示中添加,在python3中,range的作用相当于python的xrange


range creates a list, so if you do range(1, 10000000) it creates a list in memory with 9999999 elements.

xrange is a generator, so it is a sequence object is a that evaluates lazily.

这是正确的,但是在python 3中,.range()将由python 2 .xrange()实现。如果需要实际生成列表,则需要执行以下操作:

1
list(range(1,100))


记住,使用timeit模块测试哪一小段代码更快!

1
2
3
4
$ 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

就我个人而言,我总是使用.range(),除非我处理的是非常大的列表——正如你所看到的,从时间上看,对于一个有一百万个条目的列表,额外的开销只有0.04秒。正如corey指出的那样,在python 3.0.xrange()中,.range()无论如何都会给你很好的迭代器行为。


xrange只存储范围参数并根据需要生成数字。但是,Python的C实现目前将其参数限制为C long:

1
2
xrange(2**32-1, 2**32+1)  # When long is 32 bits, OverflowError: Python int too large to convert to C long
range(2**32-1, 2**32+1)   # OK --> [4294967295L, 4294967296L]

注意,在python 3.0中,只有range,它的行为类似于2.x xrange,但没有对最小和最大端点的限制。


xrange返回一个迭代器,一次只在内存中保留一个数字。range将整个数字列表保存在内存中。


一定要花些时间参考图书馆。你对它越熟悉,你就越能更快地找到这样的问题的答案。特别重要的是关于内置对象和类型的前几章。

The advantage of the xrange type is that an xrange object will always
take the same amount of memory, no matter the size of the range it represents.
There are no consistent performance advantages.

另一种查找有关python结构的快速信息的方法是docstring和帮助函数:

1
2
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)


我很震惊没人看医生:

This function is very similar to range(), but returns an xrange object instead of a list. This is an opaque sequence type which yields the same values as the corresponding list, without actually storing them all simultaneously. The advantage of xrange() over range() is minimal (since xrange() still has to create the values when asked for them) except when a very large range is used on a memory-starved machine or when all of the range’s elements are never used (such as when the loop is usually terminated with break).


range creates a list, so if you do range(1, 10000000) it creates a list in memory with 10000000 elements.
xrange is a generator, so it evaluates lazily.

这给您带来了两个优势:

  • 您可以迭代较长的列表,而无需获取MemoryError
  • 当它缓慢地解析每个数字时,如果您提前停止迭代,就不会浪费时间创建整个列表。

  • 在这个简单的例子中,您会发现xrangerange的优势:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import timeit

    t1 = timeit.default_timer()
    a = 0
    for i in xrange(1, 100000000):
        pass
    t2 = timeit.default_timer()

    print"time taken:", (t2-t1)  # 4.49153590202 seconds

    t1 = timeit.default_timer()
    a = 0
    for i in range(1, 100000000):
        pass
    t2 = timeit.default_timer()

    print"time taken:", (t2-t1)  # 7.04547905922 seconds

    上面的例子并没有反映出在xrange的情况下任何实质上更好的情况。

    现在看看下面的情况,与xrange相比,range确实很慢。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import timeit

    t1 = timeit.default_timer()
    a = 0
    for i in xrange(1, 100000000):
        if i == 10000:
            break
    t2 = timeit.default_timer()

    print"time taken:", (t2-t1)  # 0.000764846801758 seconds

    t1 = timeit.default_timer()
    a = 0
    for i in range(1, 100000000):
        if i == 10000:
            break
    t2 = timeit.default_timer()

    print"time taken:", (t2-t1)  # 2.78506207466 seconds

    使用range,它已经创建了一个从0到100000000(耗时)的列表,但是xrange是一个生成器,它只根据需要生成数字,也就是说,如果迭代继续的话。

    在python-3中,range功能的实现与python-2中xrange功能的实现是相同的,而在python-3中,它们已经废除了xrange功能。

    快乐编码!!


    这是出于优化的原因。

    range()将创建从开始到结束的值列表(0..20)。这将成为一个非常大范围的昂贵操作。

    另一方面,xrange()更加优化。它只在需要时计算下一个值(通过xrange sequence对象),不会像range()那样创建所有值的列表。


    range(x,y)返回x和y之间每个数字的列表。如果使用for循环,则range的速度较慢。实际上,range的指数范围更大。range(x.y)将打印出x和y之间所有数字的列表。

    xrange(x,y)返回xrange(x,y),但如果使用for循环,则xrange更快。xrange的指数范围较小。xrange将不仅打印出xrange(x,y),还将保留其中的所有数字。

    1
    2
    3
    4
    [In] range(1,10)
    [Out] [1, 2, 3, 4, 5, 6, 7, 8, 9]
    [In] xrange(1,10)
    [Out] xrange(1,10)

    如果您使用一个for循环,那么它将工作。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    [In] for i in range(1,10):
            print i
    [Out] 1
          2
          3
          4
          5
          6
          7
          8
          9
    [In] for i in xrange(1,10):
             print i
    [Out] 1
          2
          3
          4
          5
          6
          7
          8
          9

    在使用循环时没有太大的区别,尽管只是打印循环时有区别!


    range():range(1,10)返回从1到10个数字的列表,并将整个列表保存在内存中。

    xrange():与range()类似,但不返回列表,而是返回一个按需生成范围中数字的对象。对于循环,这比range()稍快,内存效率更高。xrange()类似于迭代器的对象,并根据需要生成数字。(lazy evaluation)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    In [1]: range(1,10)

    Out[1]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

    In [2]: xrange(10)

    Out[2]: xrange(10)

    In [3]: print xrange.__doc__

    xrange([start,] stop[, step]) -> xrange object

    在Python 2。

    range(x)返回在内存中用x元素创建的列表。

    1
    2
    3
    >>> a = range(5)
    >>> a
    [0, 1, 2, 3, 4]

    xrange(x)返回一个xrange对象,它是一个按需生成数字的生成器对象。它们是在for循环(延迟计算)期间计算的。

    对于循环,这比range()稍快,内存效率更高。

    1
    2
    3
    >>> b = xrange(5)
    >>> b
    xrange(5)


    其他一些答案提到,python 3删除了2.x的range,并将2.x的xrange重命名为range。但是,除非您使用3.0或3.1(任何人都不应该使用),否则它实际上是一种有点不同的类型。

    如3.1文件所述:

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

    但是,在3.2+中,range是一个完整的序列,它支持扩展片和collections.abc.Sequence的所有方法,其语义与list相同。*

    而且,至少在cpython和pypy(目前仅有的两个3.2+实现)中,它还具有indexcount方法和in运算符(只要只传递整数)的固定时间实现。这意味着写123456 in r在3.2+中是合理的,而在2.7或3.1中则是一个可怕的想法。

    *事实上,issubclass(xrange, collections.Sequence)返回Truein 2.6-2.7 and 3.0-3.1 is a bug that was fixed in 3.2 and not backported.


    当在循环中对xrange测试范围时(我知道我应该使用timeit,但这是使用一个简单的列表理解示例从内存中快速破解出来的),我发现了以下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import time

    for x in range(1, 10):

        t = time.time()
        [v*10 for v in range(1, 10000)]
        print"range:  %.4f" % ((time.time()-t)*100)

        t = time.time()
        [v*10 for v in xrange(1, 10000)]
        print"xrange: %.4f" % ((time.time()-t)*100)

    它给出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    $python range_tests.py
    range:  0.4273
    xrange: 0.3733
    range:  0.3881
    xrange: 0.3507
    range:  0.3712
    xrange: 0.3565
    range:  0.4031
    xrange: 0.3558
    range:  0.3714
    xrange: 0.3520
    range:  0.3834
    xrange: 0.3546
    range:  0.3717
    xrange: 0.3511
    range:  0.3745
    xrange: 0.3523
    range:  0.3858
    xrange: 0.3997 <- garbage collection?

    或者,在for循环中使用xrange:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    range:  0.4172
    xrange: 0.3701
    range:  0.3840
    xrange: 0.3547
    range:  0.3830
    xrange: 0.3862 <- garbage collection?
    range:  0.4019
    xrange: 0.3532
    range:  0.3738
    xrange: 0.3726
    range:  0.3762
    xrange: 0.3533
    range:  0.3710
    xrange: 0.3509
    range:  0.3738
    xrange: 0.3512
    range:  0.3703
    xrange: 0.3509

    我的代码段测试是否正确?对较慢的xrange实例有何评论?或者一个更好的例子:—)


    python中的xrange()和range()的工作方式与用户的工作方式类似,但当我们讨论如何使用这两个函数来分配内存时,就会有不同。

    当我们使用range()时,我们为它正在生成的所有变量分配内存,因此不建议在生成的变量数量较大时使用。

    另一方面,xrange()一次只能生成一个特定的值,并且只能与for循环一起用于打印所需的所有值。


    阅读以下文章,了解用图形分析比较range和xrange。

    python范围与xrange


    range生成整个列表并返回它。xrange不——它根据需要生成列表中的数字。


    xrange使用迭代器(动态生成值),range返回一个列表。


    什么?range在运行时返回静态列表。xrange返回一个object(虽然它肯定不是一个生成器,但它的作用类似于生成器),在需要时从中生成值。

    何时使用哪个?

    • 如果你想生成一个大范围的列表,比如10亿,尤其是当你有一个像手机这样的"记忆敏感系统"时,使用EDOCX1[1]。
    • 如果您想对列表进行多次迭代,请使用range

    ps:python 3.x的range函数==python 2.x的xrange函数。


    小参数的range(..)xrange(..)的差异减小:

    1
    2
    3
    4
    5
    $ 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

    在这种情况下,xrange(100)的效率仅提高20%。


    大家都解释得很清楚。但我想亲自去看看。我使用Python 3。所以,我打开了资源监视器(在Windows中!),首先,首先执行以下命令:

    1
    2
    3
    a=0
    for i in range(1,100000):
        a=a+i

    然后检查"使用中"内存的变化。这是微不足道的。然后,我运行了以下代码:

    1
    2
    for i in list(range(1,100000)):
        a=a+i

    它立刻占用了大量的内存。我深信不疑。你可以自己试试。

    如果您使用的是python 2X,那么在第一个代码中将"range()"替换为"xrange()",将"list(range())"替换为"range()"。


    对于扫描/打印0-n项的要求,range和xrange的工作方式如下。

    range()-在内存中创建一个新列表,并获取整个0到n个项目(总共n+1)并打印它们。xrange()-创建一个迭代器实例,该实例扫描所有项,只将当前遇到的项保存到内存中,因此始终使用相同的内存量。

    如果所需元素只是在列表的开头,那么它可以节省大量的时间和内存。


    此外,如果是,list(xrange(...))将等同于range(...)

    所以list是慢的。

    另外,xrange确实没有完全完成序列。

    这就是为什么它不是一个列表,它是一个xrange对象


    range返回一个列表,而xrange返回一个xrange对象,该对象占用相同的内存,与范围大小无关,在这种情况下,每次迭代只生成一个元素并可用,而在使用range的情况下,所有元素都会同时生成并在内存中可用。


    range:-range将一次填充所有内容。这意味着range中的每个数字都将占用内存。

    xrange:-xrange类似于generator,当你想要数字的范围,但你不希望它们被存储时,它就会出现在图片中,就像你想在for循环中使用时一样。这样内存效率很高。


    来自帮助文档。

    Python 2.7.12

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    >>> print range.__doc__
    range(stop) -> list of integers
    range(start, stop[, step]) -> list of integers

    Return a list containing an arithmetic progression of integers.
    range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
    When step is given, it specifies the increment (or decrement).
    For example, range(4) returns [0, 1, 2, 3].  The end point is omitted!
    These are exactly the valid indices for a list of 4 elements.

    >>> print xrange.__doc__
    xrange(stop) -> xrange object
    xrange(start, stop[, step]) -> xrange object

    Like range(), but instead of returning a list, returns an object that
    generates the numbers in the range on demand.  For looping, this is
    slightly faster than range() and more memory efficient.

    Python 3.5.2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    >>> print(range.__doc__)
    range(stop) -> range object
    range(start, stop[, step]) -> range object

    Return an object that produces a sequence of integers from start (inclusive)
    to stop (exclusive) by step.  range(i, j) produces i, i+1, i+2, ..., j-1.
    start defaults to 0, and stop is omitted!  range(4) produces 0, 1, 2, 3.
    These are exactly the valid indices for a list of 4 elements.
    When step is given, it specifies the increment (or decrement).

    >>> print(xrange.__doc__)
    Traceback (most recent call last):
      File"<stdin>", line 1, in <module>
    NameError: name 'xrange' is not defined

    差别是明显的。在python 2.x中,range返回一个列表,xrange返回一个xrange对象,该对象是不可维护的。

    在python 3.x中,range成为python 2.x的xrange,并删除xrange


    请参阅本帖了解range和xrange之间的区别:

    引述:

    range returns exactly what you think: a list of consecutive
    integers, of a defined length beginning with 0. xrange, however,
    returns an"xrange object", which acts a great deal like an iterator