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创建一个列表,因此如果你...

问题描述:

显然 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 是一个生成器,因此它会延迟评估。

这给您带来两个好处:

  1. 您可以迭代更长的列表而无需获取MemoryError

  2. 由于它会懒惰地解析每个数字,如果您尽早停止迭代,就不会浪费时间创建整个列表。

解决方案 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 重命名xrangerange。 但是,除非您使用的是 3.0 或 3.1(没有人应该使用),否则它实际上是一种略有不同的类型。

正如3.1 文档所述:

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

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

而且,至少在 CPython 和 PyPy(目前仅有的两个 3.2+ 实现)中,它还具有indexcount方法以及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变为xrangePython 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 对象”,其作用很像迭代器

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1043  
  IPD(Integrated Product Development,集成产品开发)是一种系统化的产品开发方法论,旨在通过跨职能团队的协作,优化产品开发的效率和质量。IPD流程强调从市场需求出发,通过并行工程、跨部门协作和阶段性评审,确保产品从概念到上市的每个环节都高效且可控。随着敏捷开发方法的普及,越来越多的企业开始...
华为IPD流程   41  
  随着企业产品开发复杂度的提升以及市场需求的快速变化,传统的产品开发模式逐渐显现出局限性。集成产品开发(IPD)流程与敏捷开发(Agile Development)作为两种主流的开发方法论,分别从系统化管理和快速响应需求的角度为企业提供了解决方案。然而,单独使用其中一种方法往往无法完全满足企业在效率、质量和创新上的多重需...
华为IPD流程   35  
  华为IPD(Integrated Product Development,集成产品开发)流程是华为公司成功的关键因素之一。它不仅帮助华为在技术上实现了快速创新,还通过市场导向确保了产品的商业成功。IPD流程通过整合技术与市场双驱动,实现了从需求定义到产品交付的全生命周期管理。这种模式不仅提高了产品的开发效率,还降低了市...
IPD流程中PDCP是什么意思   32  
  在研发领域,集成产品开发(IPD)流程已经成为企业提升创新效率和市场竞争力的重要手段。然而,资源分配的不合理往往是制约IPD流程效率的关键因素之一。无论是人力资源、财务资源还是技术资源,如何高效分配直接关系到项目的成功与否。优化资源分配不仅能够缩短产品开发周期,还能降低研发成本,提升产品的市场竞争力。因此,掌握资源分配...
IPD流程中CDCP   34  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用