798

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

for i in range(0, 20):
for i in xrange(0, 20):
4

28 回答 28

941

在 Python 2.x 中:

  • range创建一个列表,所以如果你这样做range(1, 10000000),它会在内存中创建一个包含9999999元素的列表。

  • xrange是一个惰性求值的序列对象。

在 Python 3 中:

  • range相当于 Python 2 的xrange. 要获取列表,您必须明确使用list(range(...)).
  • xrange不复存在。
于 2008-09-18T17:55:13.913 回答
235

range 创建一个列表,所以如果你这样做range(1, 10000000),它会在内存中创建一个包含9999999元素的列表。

xrange 是一个生成器,所以它是一个序列对象,它是一个惰性求值的对象。

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

list(range(1,100))
于 2008-09-18T18:08:19.110 回答
118

请记住,使用该timeit模块来测试哪个小代码片段更快!

$ 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.0xrange()中将消失,并且range()无论如何都会给你很好的迭代器行为。

于 2008-09-18T22:11:15.530 回答
69

xrange仅存储范围参数并按需生成数字。然而,Python 的 C 实现目前将其 args 限制为 C long:

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,但没有对最小和最大端点的限制。

于 2008-09-18T18:13:44.180 回答
42

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

于 2008-09-18T17:55:00.140 回答
32

一定要花一些时间阅读图书馆参考资料。您对它越熟悉,就越能更快地找到此类问题的答案。尤其重要的是关于内置对象和类型的前几章。

xrange 类型的优点是 xrange 对象将始终占用相同数量的内存,无论它表示的范围大小如何。没有一致的性能优势。

另一种快速查找有关 Python 构造信息的方法是文档字符串和帮助函数:

print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
于 2008-09-18T17:55:59.137 回答
17

文档清楚地写道:

此函数与 非常相似range(),但返回一个xrange对象而不是列表。这是一种不透明的序列类型,它产生与相应列表相同的值,但实际上并没有同时存储它们。xrange()over的优势range()是最小的(因为xrange()仍然必须在被要求时创建值),除非在内存不足的机器上使用非常大的范围或从未使用过所有范围的元素(例如当循环通常以 ) 结尾break

于 2014-04-07T06:25:25.353 回答
15

你会在这个简单的例子中发现xrangeover的优势:range

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.

现在看下面的情况range,与xrange.

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 中的相同,而在 Python-3 中xrange它们已经取消xrange

编码快乐!!

于 2016-10-22T11:34:02.377 回答
14

range 创建一个列表,因此如果您执行 range(1, 10000000) 它会在内存中创建一个包含 10000000 个元素的列表。xrange 是一个生成器,因此它的评估是惰性的。

这给您带来了两个好处:

  1. 您可以迭代更长的列表而无需获取MemoryError.
  2. 由于它懒惰地解析每个数字,如果您提前停止迭代,您将不会浪费时间创建整个列表。
于 2008-09-18T18:44:38.647 回答
12

这是出于优化的原因。

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

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

于 2008-09-18T17:59:46.040 回答
10

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

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

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
于 2015-06-23T08:16:59.883 回答
10

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

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

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

如果你使用for循环,那么它会工作

[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

使用循环时没有太大区别,但仅打印时有区别!

于 2016-07-12T00:05:27.750 回答
7

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

正如3.1 文档所说:

Range 对象的行为很少:它们只支持索引、迭代和len函数。

然而,在 3.2+ 中,range它是一个完整的序列——它支持扩展切片,以及collections.abc.Sequence与 a 具有相同语义的所有方法list*

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


*在 2.6-2.7 和 3.0-3.1中issubclass(xrange, collections.Sequence)返回的事实是在 3.2 中修复且未向后移植的错误。True

于 2015-05-06T21:57:10.227 回答
7

在 python 2.x 中

range(x)返回一个列表,该列表在内存中使用 x 个元素创建。

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

xrange(x)返回一个 xrange 对象,它是一个生成器 obj,它根据需要生成数字。它们是在 for 循环(惰性评估)期间计算的。

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

>>> b = xrange(5)
>>> b
xrange(5)
于 2016-02-28T09:42:31.563 回答
6

在循环中针对 xrange 测试 range 时(我知道我应该使用timeit,但这是使用简单的列表理解示例从内存中迅速破解的)我发现以下内容:

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)

这使:

$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:

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 实例有何评论?或者一个更好的例子:-)

于 2011-03-18T12:04:59.797 回答
4

python 中的 xrange() 和 range() 的工作方式与 user 类似,但是当我们讨论使用这两个函数时如何分配内存时,区别就来了。

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

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

于 2016-01-19T12:48:45.973 回答
3

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

于 2008-09-18T17:55:27.330 回答
2

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

于 2008-09-18T17:55:30.933 回答
2

什么?
range在运行时返回一个静态列表。
xrange返回一个object(它的作用就像一个生成器,尽管它肯定不是一个),在需要时从中生成值。

什么时候用哪个?

  • 如果xrange你想为一个巨大的范围生成一个列表,比如 10 亿,尤其是当你有一个像手机这样的“内存敏感系统”时。
  • range如果您想多次迭代列表,请使用。

PS:Python 3.x 的range函数 == Python 2.x 的xrange函数。

于 2014-11-26T08:18:28.763 回答
2

每个人都已经解释得很清楚了。但我想让它亲眼看到。我使用python3。因此,我打开了资源监视器(在 Windows 中!),首先,首先执行以下命令:

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

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

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

它立即占用了大量内存。而且,我被说服了。你可以自己试试。

如果您使用的是 Python 2X,则将第一个代码中的“range()”替换为“xrange()”,将“list(range())”替换为“range()”。

于 2017-07-24T10:37:26.743 回答
2

来自帮助文档。

Python 2.7.12

>>> 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

>>> 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变为xrangePython 2.x,并被xrange删除。

于 2017-08-19T05:28:15.627 回答
2

range()在 Python 中2.x

这个函数本质上range()是 Python 中可用的旧函数,它2.x返回一个list包含指定范围内元素的对象实例。

但是,在初始化具有一系列数字的列表时,这种实现效率太低了。例如,for i in range(1000000)在内存和时间使用方面,执行命令将是一个非常昂贵的命令,因为它需要将此列表存储到内存中。


range()在 Python3.xxrange()Python 中2.x

Python3.x引入了一个较新的实现range()(而较新的实现已经在 Python 中2.x通过该xrange()函数可用)。

range()漏洞利用了一种称为惰性评估的策略。较新的实现不是在范围内创建大量元素列表,而是引入了 class range,一个轻量级对象,表示给定范围内所需的元素,而不是将它们显式存储在内存中(这听起来像生成器,但惰性求值的概念是不同的)。


例如,考虑以下情况:

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

# Python 3.x
>>> a = range(10)
>>> type(a)
<class 'range'>
于 2020-03-29T17:06:31.653 回答
1

关于扫描/打印 0-N 个项目的要求,range 和 xrange 的工作方式如下。

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

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

于 2014-01-15T12:45:29.323 回答
1

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

于 2015-01-03T06:31:21.780 回答
1

对于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

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

于 2015-05-30T11:23:20.070 回答
1

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

xrange :-xrange 类似于生成器,当您想要数字范围但又不想存储它们时,它会出现,就像您想在 for 循环中使用时一样。所以内存效率高。

于 2017-01-10T06:00:16.390 回答
1

此外, if dolist(xrange(...))将等同于range(...).

list慢也是如此。

xrange真的没有完全完成序列

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

于 2018-10-08T05:46:37.800 回答
-1

请参阅此帖子以查找 range 和 xrange 之间的区别:

去引用:

range完全按照您的想法返回:一个连续整数列表,定义长度以 0 开头xrange。但是,返回一个"xrange object",它的作用非常类似于迭代器

于 2008-09-18T17:54:40.467 回答