Python 2.X 中的 range 和 xrange 函数有什么区别?
-
01-07-2019 - |
题
显然 xrange 更快,但我不知道为什么它更快(除了到目前为止的轶事之外没有证据表明它更快)或者除此之外还有什么不同
for i in range(0, 20):
for i in xrange(0, 20):
解决方案
range 创建一个列表,所以如果你这样做 range(1, 10000000)
它在内存中创建一个列表 9999999
元素。
xrange
是一个延迟计算的序列对象。
应该从@Thiago的提示中添加,在python3中,range相当于python的xrange
其他提示
range 创建一个列表,所以如果你这样做
range(1, 10000000)
它在内存中创建一个列表9999999
元素。
xrange
是一个生成器,所以它是一个序列对象是一个懒惰地评估。
这是事实,但在 Python 3 中, .range()
将由Python 2实现 .xrange()
. 。如果您需要实际生成列表,您将需要执行以下操作:
list(range(1,100))
请记住,使用 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.0 中 .xrange()
将会消失并且 .range()
无论如何,会给你很好的迭代器行为。
xrange
仅存储范围参数并根据需要生成数字。然而,Python 的 C 实现目前将其参数限制为 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
但没有最小和最大终点的限制。
xrange 返回一个迭代器,一次只在内存中保留一个数字。range 将整个数字列表保存在内存中。
一定要花一些时间与 库参考. 。你越熟悉它,你就能越快找到此类问题的答案。特别重要的是关于内置对象和类型的前几章。
Xrange类型的优点是Xrange对象将始终采用相同数量的内存,无论其代表范围的大小如何。没有一致的性能优势。
查找有关 Python 构造的快速信息的另一种方法是文档字符串和帮助函数:
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
range 创建一个列表,因此如果执行 range(1, 10000000) ,它会在内存中创建一个包含 10000000 个元素的列表。xrange 是一个生成器,因此它会延迟计算。
这给你带来两个好处:
- 您可以迭代更长的列表而无需获得
MemoryError
. - 由于它会惰性地解析每个数字,因此如果您尽早停止迭代,就不会浪费时间创建整个列表。
我很震惊没有人读 文档:
这个功能非常类似于
range()
, ,但返回一个xrange
对象而不是列表。这是一种不透明的序列类型,它产生与相应列表相同的值,但实际上并不同时存储它们。优点xrange()
超过range()
是最小的(因为xrange()
仍然必须在要求时创建值)除非在内存匮乏的机器上使用非常大的范围或从未使用该范围的所有元素时(例如当循环通常以以下方式终止时)break
).
这是出于优化原因。
range() 将创建一个从开始到结束的值列表(0 ..在您的示例中为 20)。在非常大的范围内,这将成为一项昂贵的操作。
另一方面,xrange() 则更加优化。它只会在需要时计算下一个值(通过 xrange 序列对象),并且不会像 range() 那样创建所有值的列表。
你会发现它的优点 xrange
超过 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
功能与 xrange
在Python-2中,虽然他们已经废除了 xrange
在Python-3中
快乐编码!
范围(): range(1, 10) 返回一个包含 1 到 10 个数字的列表,并将整个列表保存在内存中。
x 范围(): 与 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
range(x,y)
如果您使用 a,则返回 x 和 y 之间每个数字的列表 for
循环,然后 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
使用循环时没有太大区别,但仅打印时有区别!
在Python 2.x中
范围(x) 返回一个在内存中创建的包含 x 个元素的列表。
>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]
x范围(x) 返回一个 xrange 对象,它是一个生成器 obj,可以根据需要生成数字。它们是在 for 循环(惰性求值)期间计算的。
对于循环,这比 range() 稍快并且内存效率更高。
>>> b = xrange(5)
>>> b
xrange(5)
在循环中针对 xrange 测试范围时(我知道我应该使用 计时, ,但这很快就被一个简单的列表理解示例从内存中破解了)我发现了以下内容:
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 实例有什么评论吗?或者一个更好的例子:-)
其他一些答案提到 Python 3 消除了 2.x range
并重命名为2.x xrange
到 range
. 。然而,除非您使用 3.0 或 3.1(没有人应该使用),否则它实际上是一种有些不同的类型。
作为 3.1 文档 说:
Range 对象的行为很少:它们只支持索引、迭代和
len
功能。
然而,在 3.2+ 中, range
是一个完整的序列——它支持扩展切片,并且支持扩展切片的所有方法 collections.abc.Sequence
与 a 具有相同的语义 list
.*
而且,至少在 CPython 和 PyPy(当前存在的仅有的两个 3.2+ 实现)中,它还具有以下常量时间实现: index
和 count
方法和 in
运算符(只要您只传递整数)。这意味着写 123456 in r
在 3.2+ 中是合理的,而在 2.7 或 3.1 中这将是一个可怕的想法。
* 事实是 issubclass(xrange, collections.Sequence)
回报 True
2.6-2.7 和 3.0-3.1 中是 一个错误 该问题已在 3.2 中修复且未向后移植。
python 中的 xrange() 和 range() 与 user 的工作方式类似,但是当我们讨论使用这两个函数时如何分配内存时,就会出现差异。
当我们使用 range() 时,我们为其生成的所有变量分配内存,因此不建议使用较大的编号。要生成的变量。
另一方面,xrange() 一次仅生成一个特定值,并且只能与 for 循环一起使用来打印所需的所有值。
range 生成整个列表并返回它。xrange 不会——它根据需要生成列表中的数字。
请阅读以下文章,通过图形分析对 range 和 xrange 进行比较。
xrange 使用迭代器(动态生成值),range 返回一个列表。
什么?
range
在运行时返回静态列表。
xrange
返回一个 object
(它的作用就像一个生成器,尽管它肯定不是一个)根据需要生成值。
什么时候用哪个?
- 使用
xrange
如果您想生成一个巨大范围的列表,例如 10 亿,特别是当您拥有像手机这样的“内存敏感系统”时。 - 使用
range
如果您想多次迭代列表。
附:Python 3.x 的 range
函数 == Python 2.x 的 xrange
功能。
对于扫描/打印 0-N 个项目的要求, range 和 xrange 的工作原理如下。
range() - 在内存中创建一个新列表,并获取整个 0 到 N 个项目(总共 N+1)并打印它们。xrange() - 创建一个迭代器实例,扫描项目并仅将当前遇到的项目保留到内存中,因此始终使用相同数量的内存。
如果所需的元素位于列表的开头,那么它可以节省大量的时间和内存。
对于较小的参数,差异会减小 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%。
大家都已经解释得很清楚了。但我想让它亲眼看看。我用的是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()”。
范围 返回一个 列表 尽管 范围 返回一个 范围 无论范围大小如何,它都占用相同的内存,在这种情况下,每次迭代仅生成一个元素并可用,而在使用范围的情况下,所有元素都会立即生成并在内存中可用。
range :-range 将一次性填充所有内容。这意味着该范围内的每个数字都将占用内存。
xrange :-xrange 类似于生成器,当您想要数字范围但不希望存储它们时(例如当您想在 for 循环中使用时),它就会出现。这样可以节省内存。
来自帮助文档。
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
变成 xrange
Python 2.x 的,以及 xrange
已移除。
另外,如果做 list(xrange(...))
将相当于 range(...)
.
所以 list
是慢的。
还 xrange
确实没有完全完成序列
这就是为什么它不是一个列表,而是一个 xrange
目的
看到这个 邮政 查找 range 和 xrange 之间的差异:
去引用:
range
返回的正是您的想法:连续整数的列表,其定义长度从0开始。xrange
, 但是,返回 “x范围对象”, ,它的作用很像迭代器