Python 2.X 中的 range 和 xrange 函数有什么区别?
- 2024-12-12 08:40:00
- admin 原创
- 80
问题描述:
显然 xrange 更快,但我不知道为什么它更快(并且到目前为止,除了传闻之外没有其他证据证明它更快),或者除此之外还有什么不同
for i in range(0, 20):
for i in xrange(0, 20):
解决方案 1:
在 Python 2.x 中:
range
创建一个列表,因此如果你这样做range(1, 10000000)
,它会在内存中创建一个包含9999999
元素的列表。xrange
是一个延迟评估的序列对象。
在 Python 3 中:
range
相当于 Python 2 中的xrange
。要获取列表,您必须明确使用list(range(...))
。xrange
不再存在。
解决方案 2:
range 会创建一个列表,因此如果你这样做
range(1, 10000000)
,它会在内存中创建一个包含9999999
元素的列表。
xrange
是一个生成器,所以它是一个序列对象,是一个延迟评估的对象。
这是真的,但在 Python 3 中,range()
将由 Python 2 实现xrange()
。如果您需要实际生成列表,则需要执行以下操作:
list(range(1,100))
解决方案 3:
记住,使用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()
无论如何都会为您提供良好的迭代器行为。
解决方案 4:
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
,但没有对最小和最大端点的限制。
解决方案 5:
xrange 返回一个迭代器,并且一次只在内存中保留一个数字。range 将整个数字列表保存在内存中。
解决方案 6:
花点时间阅读一下《库参考》。你对它越熟悉,你就能越快找到这类问题的答案。关于内置对象和类型的前几章尤其重要。
xrange 类型的优点是,无论 xrange 对象所代表的范围有多大,它总是占用相同数量的内存。没有一致的性能优势。
查找有关 Python 构造的快速信息的另一种方法是文档字符串和帮助功能:
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
解决方案 7:
来自文档:
此函数与 非常相似
range()
,但返回的是xrange
对象而不是列表。这是一个不透明的序列类型,它产生的值与相应的列表相同,但实际上不会同时存储它们。xrange()
相比的优势range()
很小(因为xrange()
在需要时仍必须创建值),除非在内存不足的机器上使用非常大的范围,或者范围的所有元素从未使用过(例如,当循环通常以 终止时break
)。
解决方案 8:
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
与 Python-2 相同,但在 Python-3 中xrange
已将其取消。xrange
编码快乐!
解决方案 9:
range 创建一个列表,因此如果你执行 range(1, 10000000),它会在内存中创建一个包含 10000000 个元素的列表。xrange 是一个生成器,因此它会延迟评估。
这给您带来两个好处:
您可以迭代更长的列表而无需获取
MemoryError
。由于它会懒惰地解析每个数字,如果您尽早停止迭代,就不会浪费时间创建整个列表。
解决方案 10:
这是出于优化的原因。
range() 将创建一个从开始到结束的值列表(在您的示例中为 0 .. 20)。对于非常大的范围,这将成为一项昂贵的操作。
另一方面,xrange() 更加优化。它只会在需要时计算下一个值(通过 xrange 序列对象),而不会像 range() 那样创建所有值的列表。
解决方案 11:
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
解决方案 12:
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)
,而且还会保留其中的所有数字。
[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
使用循环时没有太大区别,但仅打印时有区别!
解决方案 13:
其他一些答案提到 Python 3 消除了 2.xrange
并将 2.x 重命名xrange
为range
。 但是,除非您使用的是 3.0 或 3.1(没有人应该使用),否则它实际上是一种略有不同的类型。
正如3.1 文档所述:
Range 对象的行为很少:它们仅支持索引、迭代和
len
函数。
然而,在 3.2+ 中,是一个完整的序列 - 它支持扩展切片,以及与 具有相同语义range
的所有方法。*collections.abc.Sequence
`list`
而且,至少在 CPython 和 PyPy(目前仅有的两个 3.2+ 实现)中,它还具有index
和count
方法以及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
解决方案 14:
在 Python 2.x 中
range(x)返回一个在内存中创建的包含 x 个元素的列表。
>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]
xrange(x)返回一个 xrange 对象,它是一个生成器对象,可根据需要生成数字。它们是在 for 循环(惰性求值)期间计算的。
对于循环,这比 range() 稍快并且更节省内存。
>>> b = xrange(5)
>>> b
xrange(5)
解决方案 15:
当在循环中测试 range 与 xrange 时(我知道我应该使用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 较慢的实例有什么意见吗?或者更好的例子 :-)
解决方案 16:
python 中的 xrange() 和 range() 对用户来说工作方式类似,但是当我们谈论如何在使用这两个函数时分配内存时,就会有所不同。
当我们使用 range() 时,我们会为其生成的所有变量分配内存,因此不建议使用大量要生成的变量。
另一方面,xrange() 一次只生成一个特定值,并且只能与 for 循环一起使用来打印所需的所有值。
解决方案 17:
range 生成整个列表并返回它。xrange 则不然——它根据需要生成列表中的数字。
解决方案 18:
xrange 使用迭代器(动态生成值),range 返回一个列表。
解决方案 19:
什么?
range
在运行时返回一个静态列表。
xrange
返回一个object
(其作用类似于生成器,尽管它肯定不是生成器),在需要时从中生成值。
何时使用哪个?
如果您想要生成一个巨大的范围(比如 10 亿)的列表,请使用它
xrange
,尤其是当您拥有像手机这样的“记忆敏感系统”时。range
如果您想多次迭代列表则使用。
PS:Python 3.x 的range
功能 == Python 2.x 的xrange
功能。
解决方案 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()”。
解决方案 21:
来自帮助文档。
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
被删除。
解决方案 22:
range()
在 Python 中2.x
该函数本质上是range()
Python 中可用的旧函数,返回包含指定范围内元素 2.x
的对象实例。list
但是,当需要初始化包含一系列数字的列表时,此实现效率太低。例如,for i in range(1000000)
执行此命令将非常昂贵,无论是内存还是时间使用量,因为它需要将此列表存储到内存中。
range()
在 Python 中3.x
以及xrange()
在 Python 中2.x
Python3.x
引入了较新的实现range()
(而较新的实现已经2.x
通过xrange()
函数在 Python 中可用)。
该range()
算法利用了一种称为惰性求值的策略。较新的实现不是在范围内创建一个巨大的元素列表,而是引入了类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'>
解决方案 23:
对于 0-N 个项目的扫描/打印要求,range 和 xrange 的工作方式如下。
range() - 在内存中创建一个新列表,取出全部 0 到 N 个项目(总共 N+1)并打印它们。xrange() - 创建一个迭代器实例,扫描所有项目并仅将当前遇到的项目保留在内存中,因此始终使用相同数量的内存。
如果所需元素位于列表的开头,那么可以节省大量时间和内存。
解决方案 24:
Range返回一个列表,而xrange返回一个xrange对象,该对象占用相同的内存,而不管范围大小,因为在这种情况下,每次迭代只生成一个元素并可用,而在使用范围的情况下,所有元素都会一次生成并可在内存中使用。
解决方案 25:
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%。
解决方案 26:
范围:-范围将一次填充所有内容,这意味着范围的每个数字都将占用内存。
xrange:-xrange 类似于生成器,当您想要数字范围但不想存储它们时它就会出现,例如当您想在 for 循环中使用它们时。因此内存效率高。
解决方案 27:
此外,如果 dolist(xrange(...))
将等同于range(...)
。
所以list
很慢。
也xrange
没有真正完成整个序列
所以这就是为什么它不是一个列表,而是一个xrange
对象
解决方案 28:
请参阅此文章来了解 range 和 xrange 之间的区别:
引用:
range
返回的结果和你想象的完全一样:一个连续整数列表,长度固定,以 0 开头。xrange
但是,它返回一个“xrange 对象”,其作用很像迭代器
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)