为什么或者为什么不呢?

有帮助吗?

解决方案

对性能,特别是当你迭代了很大范围, xrange() 通常是更好。但是,仍然有一些情况下为什么你可能会喜欢 range():

  • 在python3, range() 做什么 xrange() 用来做 xrange() 并不存在。如果你想要写代码,将运行在这两个蟒蛇2和Python3,你不能使用 xrange().

  • range() 实际上可以更快,在某些情况下,例如。如果重复同一序列的多次。 xrange() 已重建该整数的对象的每一个时间,但是 range() 会有真正整数的对象。(它将一直执行更糟糕的是在条款的记忆但是)

  • xrange() 不是用在所有情况下,一个真正的清单是必要的。例如,它不支持片或任何列表方法。

[编辑]有几个员额提及如何 range() 将升级通过的2to3工具。为了记录在案,这里的输出运行的工具,在一些样品用途的 range()xrange()

RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: ws_comma
--- range_test.py (original)
+++ range_test.py (refactored)
@@ -1,7 +1,7 @@

 for x in range(20):
-    a=range(20)
+    a=list(range(20))
     b=list(range(20))
     c=[x for x in range(20)]
     d=(x for x in range(20))
-    e=xrange(20)
+    e=range(20)

正如你可以看到,当使用一个循环或理解能力,或其中已经包list()、范围保持不变。

其他提示

不,他们都有自己的用途:

迭代时使用 xrange(),因为它可以节省内存。说:

for x in xrange(1, one_zillion):

而不是:

for x in range(1, one_zillion):

另一方面,如果你真的想要一个数字列表,请使用 range()

multiples_of_seven = range(7,100,7)
print "Multiples of seven < 100: ", multiples_of_seven

只有当您需要实际列表时,才应该在 xrange()上使用 range()。例如,当您想要修改 range()返回的列表时,或者您希望对其进行切片时。对于迭代甚至只是正常的索引, xrange()将正常工作(通常更有效)。对于非常小的列表, range() xrange()快一点,但根据您的硬件和其他各种细节,收支平衡可以长度为1或2的结果;不用担心。首选 xrange()

另一个区别是xrange()不能支持大于C ints的数字,所以如果你想使用python内置的大量支持来获得一个范围,你必须使用range()。

Python 2.7.3 (default, Jul 13 2012, 22:29:01) 
[GCC 4.7.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> range(123456787676676767676676,123456787676676767676679)
[123456787676676767676676L, 123456787676676767676677L, 123456787676676767676678L]
>>> xrange(123456787676676767676676,123456787676676767676679)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: Python int too large to convert to C long

Python 3没有这个问题:

Python 3.2.3 (default, Jul 14 2012, 01:01:48) 
[GCC 4.7.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> range(123456787676676767676676,123456787676676767676679)
range(123456787676676767676676, 123456787676676767676679)

xrange()更有效,因为它不是生成对象列表,而是一次只生成一个对象。而不是100个整数,以及它们的所有开销,以及放入它们的列表,你一次只能有一个整数。更快的生成,更好的内存使用,更高效的代码。

除非我特别需要列表,否则我总是喜欢 xrange()

range()返回一个列表,xrange()返回一个xrange对象。

xrange()有点快,而且内存效率更高。但收益不是很大。

列表使用的额外内存当然不仅仅是浪费,列表还有更多功能(切片,重复,插入,...)。可以在文档中找到确切的差异。没有骨干规则,使用所需的东西。

Python 3.0仍处于开发阶段,但IIRC range()与2.X的xrange()非常相似,list(range())可用于生成列表。

我只想说,获取带有切片和索引功能的xrange对象真的不是那么困难。我已经编写了一些非常好用的代码,并且在计算(迭代)时与xrange一样快。

from __future__ import division

def read_xrange(xrange_object):
    # returns the xrange object's start, stop, and step
    start = xrange_object[0]
    if len(xrange_object) > 1:
       step = xrange_object[1] - xrange_object[0]
    else:
        step = 1
    stop = xrange_object[-1] + step
    return start, stop, step

class Xrange(object):
    ''' creates an xrange-like object that supports slicing and indexing.
    ex: a = Xrange(20)
    a.index(10)
    will work

    Also a[:5]
    will return another Xrange object with the specified attributes

    Also allows for the conversion from an existing xrange object
    '''
    def __init__(self, *inputs):
        # allow inputs of xrange objects
        if len(inputs) == 1:
            test, = inputs
            if type(test) == xrange:
                self.xrange = test
                self.start, self.stop, self.step = read_xrange(test)
                return

        # or create one from start, stop, step
        self.start, self.step = 0, None
        if len(inputs) == 1:
            self.stop, = inputs
        elif len(inputs) == 2:
            self.start, self.stop = inputs
        elif len(inputs) == 3:
            self.start, self.stop, self.step = inputs
        else:
            raise ValueError(inputs)

        self.xrange = xrange(self.start, self.stop, self.step)

    def __iter__(self):
        return iter(self.xrange)

    def __getitem__(self, item):
        if type(item) is int:
            if item < 0:
                item += len(self)

            return self.xrange[item]

        if type(item) is slice:
            # get the indexes, and then convert to the number
            start, stop, step = item.start, item.stop, item.step
            start = start if start != None else 0 # convert start = None to start = 0
            if start < 0:
                start += start
            start = self[start]
            if start < 0: raise IndexError(item)
            step = (self.step if self.step != None else 1) * (step if step != None else 1)
            stop = stop if stop is not None else self.xrange[-1]
            if stop < 0:
                stop += stop

            stop = self[stop]
            stop = stop

            if stop > self.stop:
                raise IndexError
            if start < self.start:
                raise IndexError
            return Xrange(start, stop, step)

    def index(self, value):
        error = ValueError('object.index({0}): {0} not in object'.format(value))
        index = (value - self.start)/self.step
        if index % 1 != 0:
            raise error
        index = int(index)


        try:
            self.xrange[index]
        except (IndexError, TypeError):
            raise error
        return index

    def __len__(self):
        return len(self.xrange)

老实说,我认为整个问题有点愚蠢,而xrange应该做所有这些......

书中给出了一个很好的例子:实用Python 作者Magnus Lie Hetland

>>> zip(range(5), xrange(100000000))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]

我不建议在前面的例子中使用范围而不是xrange,尽管如此 只需要前五个数字,范围计算所有数字,这可能需要很多 时间使用xrange,这不是一个问题,因为它只计算所需的数字。

是的我读过@Brian的答案:在python 3中,range()无论如何都是一个生成器,并且xrange()不存在。

出于以下原因选择范围:

1)xrange将在较新的Python版本中消失。这为您提供了便利的兼容性。

2)范围将具有与xrange相关的效率。

好的,这里的每个人都对xrange与范围的权衡和优势有不同的看法。它们大多是正确的,xrange是一个迭代器,范围充实并创建一个实际的列表。对于大多数情况,您不会真正注意到两者之间的差异。 (您可以使用带范围的地图,但不能使用xrange,但会占用更多内存。)

然而,我认为你想听到的是,首选的选择是xrange。由于Python 3中的范围是迭代器,因此代码转换工具2to3会正确地将xrange的所有用途转换为范围,并且会因使用范围而抛出错误或警告。如果你想确保将来轻松转换你的代码,你将只使用xrange,并在你确定需要列表时列出(xrange)。我在今年(2008年)芝加哥的PyCon CPython冲刺期间学到了这一点。

  • 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__
Out[3]: xrange([start,] stop[, step]) -> xrange object

range() 做同样的事情 xrange() 用来做Python3和没有期 xrange() 存在Python3.range() 实际上可以更快的速度在一些情况如果你迭代了相同的序列多次。 xrange() 已重建该整数的对象的每一个时间,但是 range() 会有真正整数的对象。

虽然 xrange 在大多数情况下比 range 更快,但性能上的差异非常小。下面的小程序比较迭代范围 xrange

import timeit
# Try various list sizes.
for list_len in [1, 10, 100, 1000, 10000, 100000, 1000000]:
  # Time doing a range and an xrange.
  rtime = timeit.timeit('a=0;\nfor n in range(%d): a += n'%list_len, number=1000)
  xrtime = timeit.timeit('a=0;\nfor n in xrange(%d): a += n'%list_len, number=1000)
  # Print the result
  print "Loop list of len %d: range=%.4f, xrange=%.4f"%(list_len, rtime, xrtime)

下面的结果显示 xrange 确实更快,但还不足以让人流汗。

Loop list of len 1: range=0.0003, xrange=0.0003
Loop list of len 10: range=0.0013, xrange=0.0011
Loop list of len 100: range=0.0068, xrange=0.0034
Loop list of len 1000: range=0.0609, xrange=0.0438
Loop list of len 10000: range=0.5527, xrange=0.5266
Loop list of len 100000: range=10.1666, xrange=7.8481
Loop list of len 1000000: range=168.3425, xrange=155.8719

所以一定要使用 xrange ,但除非你在受限制的硬件上,否则不要太担心它。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top