显然xrange更快,但我不知道它为什么更快(并且除了到目前为止只是口头陈述的证据外没有其他证据),也不知道除了这个之外还有什么不同之处
for i in range(0, 20):
for i in xrange(0, 20):
显然xrange更快,但我不知道它为什么更快(并且除了到目前为止只是口头陈述的证据外没有其他证据),也不知道除了这个之外还有什么不同之处
for i in range(0, 20):
for i in xrange(0, 20):
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
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
使用循环时并没有太大的区别,但在仅打印输出时是有区别的!
range
并将2.x版本的xrange
重命名为range
。但是,除非您使用的是3.0或3.1(没有人应该使用),否则它实际上是一个略有不同的类型。但是,在3.2+中,范围对象几乎没有行为:它们仅支持索引、迭代和
len
函数。
range
是一个完整的序列——它支持扩展切片,并且具有与list
相同语义的collections.abc.Sequence
的所有方法。*
至少在CPython和PyPy(目前仅有的两个3.2+实现)中,它还具有index
和count
方法以及in
运算符的常数时间实现(只要传递整数)。这意味着在3.2+中编写123456 in r
是合理的,而在2.7或3.1中则是一个可怕的想法。
issubclass(xrange, collections.Sequence)
返回True
的事实是错误,在3.2中已被修复,但未进行回溯。
在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)
在循环中测试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的较慢实例有何评论?或者有更好的示例吗?
xrange
似乎稍微快一些,尽管在Python 3中比较现在已经过时了。 - Dave Everitttimeit
的作用。它负责运行多次测试,禁用垃圾回收,使用最佳时钟而不是 time
等。 - abarnert在Python中,xrange()和range()的工作方式对于用户来说是相似的,但是它们之间的区别在于如何分配内存。
当我们使用range()时,会为所有生成的变量分配内存,因此不建议在需要生成大量变量时使用它。
另一方面,xrange()每次仅生成一个特定值,并且只能与for循环一起使用以打印所需的所有值。
range生成整个列表并返回它。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
然后检查了'In Use'内存的变化。但是变化很小。 接下来,我运行了以下代码:
for i in list(range(1,100000)):
a=a+i
它立即占用了大量的内存。我相信这一点。
如果您正在使用Python 2X,则需要在第一个代码中将'range()'替换为'xrange()',并将'list(range())'替换为'range()'。
range()
在Python 2.x
中的用法
这个函数本质上是Python 2.x
中可用的旧的range()
函数,它返回一个包含指定范围内元素的list
对象实例。
然而,当需要初始化一个数字范围的列表时,这种实现方式效率太低了。例如,执行for i in range(1000000)
命令会非常昂贵,无论是在内存使用还是时间使用方面,因为它需要将此列表存储到内存中。
range()
在Python 3.x
中的用法以及Python 2.x
中的xrange()
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'>
xrange()
不是生成器。xrange(n).__iter __()
是生成器。 - th3an0maly