为什么或者为什么不呢?


当前回答

选择范围有以下几个原因:

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

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

其他回答

我只是想说,获得一个具有切片和索引功能的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应该做所有这些…

Range()返回列表,xrange()返回xrange对象。

Xrange()更快一点,内存效率更高一点。但是收益不是很大。

列表使用的额外内存当然不仅仅是浪费,列表有更多的功能(切片、重复、插入……)。具体的区别可以在文档中找到。没有硬性规定,需要什么就用什么。

Python 3.0仍在开发中,但IIRC range()将非常类似于xrange()的2。X和list(range())可以用来生成列表。

对于性能而言,尤其是在大范围内迭代时,xrange()通常更好。然而,仍然有一些情况下你可能更喜欢range():

In python 3, range() does what xrange() used to do and xrange() does not exist. If you want to write code that will run on both Python 2 and Python 3, you can't use xrange(). range() can actually be faster in some cases - eg. if iterating over the same sequence multiple times. xrange() has to reconstruct the integer object every time, but range() will have real integer objects. (It will always perform worse in terms of memory however) xrange() isn't usable in all cases where a real list is needed. For instance, it doesn't support slices, or any list methods.

[编辑]有几篇文章提到了如何通过2to3工具升级range()。为了记录,下面是在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)

如您所见,当在for循环或推导式中使用时,或者已经使用list()包装时,range保持不变。

书中给出了一个很好的例子:Practical Python By Magnus Lie Hetland

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

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

是的,我读了@Brian的回答:在python 3中,range()是一个生成器,xrange()不存在。

选择范围有以下几个原因:

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

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