Если вы всегда предпочитаете xrange() по диапазону()?

Почему или почему?

Ответы

Ответ 1

Для производительности, особенно когда вы выполняете итерацию в большом диапазоне, xrange() обычно лучше. Тем не менее, есть еще несколько случаев, почему вы предпочитаете range():

  • В python 3, range() выполняет ли что xrange(), а xrange() не существует. Если вы хотите написать код, который будет работать как на Python 2, так и на Python 3, вы не можете использовать 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)

Как вы можете видеть, при использовании в цикле или понимании for или где уже завернутый в список() диапазон остается неизменным.

Ответ 2

Нет, они оба используют свои возможности:

Используйте 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

Ответ 3

Вы должны одобрить range() over xrange() только тогда, когда вам нужен фактический список. Например, если вы хотите изменить список, возвращаемый range(), или когда вы хотите его отрезать. Для итерации или даже просто нормальной индексации xrange() будет работать нормально (и обычно намного эффективнее). Существует точка, в которой range() бит быстрее, чем xrange() для очень маленьких списков, но в зависимости от вашего оборудования и различных других деталей безубыточность может быть результатом длины 1 или 2; не о чем беспокоиться. Предпочитают xrange().

Ответ 4

Еще одно отличие состоит в том, что xrange() не может поддерживать числа, большие, чем C int, поэтому, если вы хотите иметь диапазон, используя 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)

Ответ 5

xrange() более эффективен, потому что вместо генерации списка объектов он генерирует только один объект за раз. Вместо 100 целых чисел и всех их накладных расходов, а также списка для их ввода, у вас есть только одно целое за раз. Более быстрое поколение, лучшее использование памяти, более эффективный код.

Если мне не нужен список для чего-то, я всегда предпочитаю xrange()

Ответ 6

range() возвращает список, xrange() возвращает объект xrange.

xrange() немного быстрее и немного более эффективно. Но усиление не очень велико.

Дополнительная память, используемая списком, конечно, не просто потеряна, списки имеют больше функциональности (фрагмент, повтор, вставка,...). Точные различия можно найти в документации . Нет правила костяной косточки, используйте то, что нужно.

Python 3.0 все еще находится в разработке, но диапазон IIRC() будет очень похож на xrange() из 2.X, а list (range()) может использоваться для создания списков.

Ответ 7

Я просто хотел бы сказать, что это ДЕЙСТВИТЕЛЬНО не так сложно получить объект xrange с функциями среза и индексирования. Я написал код, который хорошо работает, и так же быстро, как xrange, когда он подсчитывает (итерации).

from __future__ import division

def read_xrange(xrange_object):
    # returns the xrange object 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 все равно должен все это сделать...

Ответ 8

Хороший пример приведен в книге: Практический Python Магнус Ли Хетланд

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

Я бы не рекомендовал использовать диапазон вместо xrange в предыдущем примере, хотя нужны только первые пять чисел, диапазон вычисляет все числа, и это может занять много времени. С помощью xrange это не проблема, потому что она вычисляет только те числа, которые необходимы.

Да, я прочитал ответ @Brian: в python 3, range() в любом случае является генератором, а xrange() не существует.

Ответ 9

Перейдите с диапазоном по следующим причинам:

1) xrange будет уходить в новых версиях Python. Это дает вам легкую совместимость в будущем.

2) диапазон будет принимать эффективность, связанную с xrange.

Ответ 10

Хорошо, все здесь как другое мнение относительно компромиссов и преимуществ xrange versus range. Они в основном правильны, xrange - это итератор, а также диапазон fleshes и создает фактический список. В большинстве случаев вы не заметите разницы между ними. (Вы можете использовать карту с диапазоном, но не с xrange, но она использует больше памяти.)

То, что я думаю, что вы хотите услышать, однако, состоит в том, что предпочтительным выбором является xrange. Поскольку диапазон в Python 3 является итератором, инструмент преобразования кода 2to3 будет правильно преобразовывать все применения xrange в диапазон и выкинет ошибку или предупреждение для использования диапазона. Если вы хотите, чтобы в будущем вы легко конвертировали свой код, вы будете использовать только xrange и список (xrange), если вы уверены, что хотите получить список. Я узнал об этом во время спринта CPython в PyCon в этом году (2008) в Чикаго.

Ответ 11

  • range(): range(1, 10) возвращает список от 1 до 10 номеров и удерживает весь список в памяти.
  • xrange(): Как range(), но вместо того, чтобы возвращать список, возвращает объект, который генерирует числа в диапазоне по запросу. Для циклизации это намного быстрее, чем range() и более эффективно. xrange() объект как итератор и генерирует числа по требованию (Lazy Evaluation).
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(), используемое в Python 3, и в Python 3 нет термина xrange(). range() может быть быстрее в каком-либо сценарии, если вы повторяете одну и ту же последовательность несколько раз. xrange() должен каждый раз восстанавливать целочисленный объект, но range() будет иметь действительные целые объекты.

Ответ 12

В то время как xrange быстрее, чем range, в большинстве случаев разница в производительности довольно минимальна. В приведенной ниже небольшой программе сравниваются итерации по 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, но если вы не находитесь на ограниченном аппаратном обеспечении, не беспокойтесь о нем слишком много.