В чем разница между функциями range и xrange в Python 2.X? - PullRequest
662 голосов
/ 18 сентября 2008

Очевидно, xrange быстрее, но я понятия не имею, почему он быстрее (и нет никаких доказательств, кроме того, что он пока что быстрее), или что кроме этого отличается от

for i in range(0, 20):
for i in xrange(0, 20):

Ответы [ 28 ]

751 голосов
/ 18 сентября 2008
Диапазон

создает список, поэтому если вы сделаете range(1, 10000000), он создаст список в памяти с 9999999 элементами.

xrange - это объект последовательности, который вычисляется лениво.

Из подсказки @ Thiago следует добавить, что в python3 range делает эквивалент xrange для python

217 голосов
/ 18 сентября 2008

range создает список, поэтому если вы делаете range(1, 10000000), он создает список в памяти с 9999999 элементами.

xrange - это генератор, поэтому - это объект последовательности - это , который вычисляется лениво

Это правда, но в Python 3 .range() будет реализован Python 2 .xrange(). Если вам нужно сгенерировать список, вам нужно будет сделать:

list(range(1,100))
108 голосов
/ 19 сентября 2008

Помните, используйте модуль timeit, чтобы проверить, какой из небольших фрагментов кода быстрее!

$ 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 секунды. И, как указывает Кори, в Python 3.0 .xrange() исчезнет, ​​а .range() в любом случае даст вам хорошее поведение итератора.

64 голосов
/ 18 сентября 2008

xrange хранит только параметры диапазона и генерирует числа по запросу. Однако реализация Python на C в настоящее время ограничивает свои аргументы C longs:

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, но без ограничений на минимальную и максимальную конечные точки.

38 голосов
/ 18 сентября 2008

xrange возвращает итератор и сохраняет в памяти только одно число за раз. Диапазон хранит весь список чисел в памяти.

28 голосов
/ 18 сентября 2008

Потратьте немного времени на Библиотечный справочник . Чем более вы знакомы с ним, тем быстрее вы сможете найти ответы на подобные вопросы. Особенно важны первые несколько глав о встроенных объектах и ​​типах.

Преимущество типа xrange заключается в том, что объект xrange всегда будет занять одинаковый объем памяти, независимо от размера диапазона, который он представляет. Нет постоянных преимуществ в производительности.

Другой способ быстро найти информацию о конструкции Python - строка документации и функция справки:

print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
13 голосов
/ 18 сентября 2008

range создает список, поэтому, если вы сделаете range (1, 10000000), он создаст список в памяти с 10000000 элементов. xrange - генератор, поэтому он оценивает лениво.

Это дает вам два преимущества:

  1. Вы можете перебирать более длинные списки, не получая MemoryError.
  2. Поскольку каждое число лениво разрешается, если вы прекратите итерацию раньше, вы не будете тратить время на создание всего списка.
13 голосов
/ 07 апреля 2014

Я в шоке, никто не читал Док :

Эта функция очень похожа на range(), но возвращает список xrange вместо списка. Это непрозрачный тип последовательности, который выдает те же значения, что и соответствующий список, фактически не сохраняя их все одновременно. Преимущество xrange() над range() минимально (так как xrange() все еще должен создавать значения при запросе их), за исключением случаев, когда очень большой диапазон используется на машине с нехваткой памяти или когда все элементы диапазона никогда не используется (например, когда цикл обычно завершается break).

11 голосов
/ 22 октября 2016

Вы найдете преимущество 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.

Теперь рассмотрим следующий случай, когда range действительно очень медленный по сравнению с xrange.

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 такая же, как и у xrange в Python-2, хотя они покончили с xrange в Python-3

Удачного кодирования!

11 голосов
/ 18 сентября 2008

Это по причинам оптимизации.

range () создаст список значений от начала до конца (0 .. 20 в вашем примере). Это станет дорогой операцией на очень больших диапазонах.

xrange (), с другой стороны, гораздо более оптимизирован. он вычисляет следующее значение только при необходимости (через объект последовательности xrange) и не создает список всех значений, которые выполняет range ().

...