【发布时间】:2010-09-10 19:56:16
【问题描述】:
显然 xrange 更快,但我不知道为什么它更快(除了传闻之外没有证据表明它更快)或者除此之外还有什么不同
for i in range(0, 20):
for i in xrange(0, 20):
【问题讨论】:
标签: python loops range python-2.x xrange
显然 xrange 更快,但我不知道为什么它更快(除了传闻之外没有证据表明它更快)或者除此之外还有什么不同
for i in range(0, 20):
for i in xrange(0, 20):
【问题讨论】:
标签: python loops range python-2.x xrange
doc 清楚地写着:
此函数与
range()非常相似,但返回的是xrange对象而不是列表。这是一个不透明的序列类型,它产生与相应列表相同的值,但实际上并没有同时存储它们。xrange()相对于range()的优势很小(因为xrange()在被要求时仍然必须创建值),除非在内存不足的机器上使用非常大的范围或所有范围的元素都从未使用过(例如循环通常以break终止时)。
【讨论】:
在 Python 2.x 中:
range 创建一个列表,因此如果您执行range(1, 10000000),它会在内存中创建一个包含9999999 元素的列表。
xrange 是一个惰性求值的序列对象。
在 Python 3 中:
range 相当于 Python 2 的 xrange。要获取列表,您必须明确使用list(range(...))。xrange 不再存在。【讨论】:
i 都是按需评估而不是初始化。
记住,使用timeit 模块来测试哪个小sn-ps 代码更快!
$ 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() 无论如何都会为您提供良好的迭代器行为。
【讨论】:
python -m timeit "for i in xrange(1000000):" " pass"
the extra overhead is only 0.04 seconds 不是正确的看待它的方式,(90.5-51.1)/51.1 = 1.771 times slower 是正确的,因为它传达了如果这是你的核心循环编程它可能会成为瓶颈。但是,如果这只是一小部分,那么 1.77 倍也不算多。
range 创建一个列表,因此如果您执行
range(1, 10000000),它会在内存中创建一个带有9999999元素的列表。
xrange是一个生成器,所以它是一个序列对象是一个,它是惰性求值的。
这是真的,但在 Python 3 中,range() 将由 Python 2 xrange() 实现。如果您需要实际生成列表,则需要执行以下操作:
list(range(1,100))
【讨论】:
typing.*)。
next(range(42)))。
range() 在 Python 中 2.x
这个函数本质上是旧的 range() 函数,它在 Python 2.x 中可用,并返回一个包含指定范围内元素的 list 对象的实例。
但是,在初始化具有一系列数字的列表时,这种实现效率太低了。例如,for i in range(1000000) 在内存和时间使用方面都是一个非常昂贵的命令,因为它需要将此列表存储到内存中。
range() 在 Python 中 3.x 和 xrange() 在 Python 中 2.x
Python 3.x 引入了 range() 的更新实现(而更新的实现已经在 Python 2.x 中通过 xrange() 函数提供)。
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'>
【讨论】:
请花一些时间与Library Reference 联系。您对它越熟悉,就越能更快地找到此类问题的答案。尤其重要的是关于内置对象和类型的前几章。
xrange 类型的优点是 xrange 对象总是 占用相同数量的内存,无论它代表的范围大小。 没有一致的性能优势。
另一种快速查找有关 Python 构造信息的方法是文档字符串和帮助函数:
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
【讨论】:
另外,如果做list(xrange(...)) 将等同于range(...)。
所以list 很慢。
还有xrange真的没有完全完成序列
所以这就是为什么它不是一个列表,它是一个 xrange 对象
【讨论】:
来自帮助文档。
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 变为 Python 2.x 的 xrange,并删除了 xrange。
【讨论】:
每个人都解释得很清楚。但我想让它亲眼看到。我使用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 循环中使用时。所以内存效率很高。
【讨论】:
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
使用循环并没有太大区别,只是打印时有区别!
【讨论】:
在这个简单的示例中,您会发现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 的情况下,上面的例子并没有更好地反映任何事情。
现在看看下面的例子,与xrange相比,range 真的很慢。
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(): 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
【讨论】:
在 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)
【讨论】:
xrange() 不是生成器。 xrange(n).__iter__()` 是。
python 中的 xrange() 和 range() 与 user 的工作方式类似,但不同之处在于我们讨论使用这两个函数时如何分配内存。
当我们使用 range() 时,我们为它生成的所有变量分配内存,因此不建议使用较大的 no。要生成的变量。
另一方面,xrange() 一次只生成一个特定的值,并且只能与 for 循环一起使用以打印所需的所有值。
【讨论】:
range 创建一个列表,因此如果您执行 range(1, 10000000) 它会在内存中创建一个包含 10000000 个元素的列表。 xrange 是一个生成器,所以它的计算是惰性的。
这会给你带来两个好处:
MemoryError。【讨论】:
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,但没有最小和最大端点的限制。
【讨论】:
对于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%。
【讨论】:
什么?range 在运行时返回一个静态列表。xrange 返回一个object(它的作用就像一个生成器,虽然它肯定不是一个),在什么时候生成值必填。
什么时候用哪个?
xrange,尤其是当您拥有像手机这样的“内存敏感系统”时。range。PS:Python 3.x 的 range 函数 == Python 2.x 的 xrange 函数。
【讨论】:
xrange 不返回生成器对象。
其他一些答案提到 Python 3 消除了 2.x 的 range 并将 2.x 的 xrange 重命名为 range。但是,除非您使用的是 3.0 或 3.1(没有人应该使用),否则它实际上是一种不同的类型。
正如the 3.1 docs 所说:
Range 对象的行为很少:它们只支持索引、迭代和
len函数。
然而,在 3.2+ 中,range 是一个完整的序列——它支持扩展切片,以及 collections.abc.Sequence 的所有方法与 list 具有相同的语义。*
而且,至少在 CPython 和 PyPy(目前仅有的两个 3.2+ 实现)中,它还具有 index 和 count 方法和 in 运算符的恒定时间实现(只要你只传递整数)。这意味着在 3.2+ 中写 123456 in r 是合理的,而在 2.7 或 3.1 中这将是一个可怕的想法。
* issubclass(xrange, collections.Sequence) 在 2.6-2.7 和 3.0-3.1 中返回 True 的事实是 a bug 在 3.2 中已修复且未向后移植。
【讨论】:
Range 返回一个 list 而 xrange 返回一个 xrange 对象,无论范围如何,它都占用相同的内存size,在这种情况下,每次迭代只生成一个元素并且可用,而在使用范围的情况下,所有元素都是一次生成并在内存中可用。
【讨论】:
关于扫描/打印 0-N 个项目的需求,range 和 xrange 的工作原理如下。
range() - 在内存中创建一个新列表并获取整个 0 到 N 项(总共 N+1)并打印它们。 xrange() - 创建一个迭代器实例,它扫描项目并仅将当前遇到的项目保留在内存中,因此始终使用相同数量的内存。
如果所需元素位于列表的开头,那么它可以节省大量时间和内存。
【讨论】:
xrange 不创建迭代器实例。它创建了一个xrange 对象,它是可迭代的,但不是迭代器——几乎(但不完全是)一个序列,就像一个列表。
查看此post 以查找 range 和 xrange 之间的区别:
引用:
range完全按照您的想法返回:连续的列表 整数,具有从 0 开始的定义长度。xrange,但是, 返回一个“xrange 对象”,它的作用很像一个迭代器
【讨论】:
xrange 不是迭代器。 range 返回的列表确实支持迭代(列表几乎是可迭代的原型示例)。 xrange 的整体好处不是“最小的”。以此类推。
在循环中针对 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
我的 sn-p 测试是否正确? xrange 较慢的实例上有任何 cmets 吗?或者一个更好的例子:-)
【讨论】:
xrange 似乎稍微快一些,尽管现在使用 Python 3 进行比较是多余的。
timeit 的用途。它负责运行多次、禁用 GC、使用最佳时钟而不是 time 等。
这是为了优化。
range() 将创建一个从头到尾的值列表(在您的示例中为 0 .. 20)。这将成为非常大范围的昂贵操作。
另一方面,xrange() 更加优化。它只会在需要时(通过 xrange 序列对象)计算下一个值,并且不会像 range() 那样创建所有值的列表。
【讨论】:
xrange 使用迭代器(动态生成值),range 返回一个列表。
【讨论】:
range 生成整个列表并返回它。 xrange 不会——它会按需生成列表中的数字。
【讨论】:
xrange 返回一个迭代器,并且一次只在内存中保留一个数字。 range 将整个数字列表保存在内存中。
【讨论】:
xrange not 返回一个迭代器。
and only keeps one number in memory at a time 其余的放在哪里请指导我..