В чем разница между функциями range и xrange в Python 2.X?
-
01-07-2019 - |
Вопрос
По-видимому, xrange быстрее, но я понятия не имею, почему это быстрее (и пока нет доказательств, кроме анекдотического, что это быстрее) или что, кроме этого, отличается
for i in range(0, 20):
for i in xrange(0, 20):
Решение
диапазон создает список, поэтому, если вы сделаете range(1, 10000000)
он создает список в памяти с помощью 9999999
элементы.
xrange
это объект последовательности, который вычисляется лениво.
Следует добавить из подсказки @Thiago, что в python3 range выполняет эквивалент xrange в python
Другие советы
диапазон создает список, поэтому, если вы сделаете
range(1, 10000000)
он создает список в памяти с помощью9999999
элементы.
xrange
является генератором, поэтому онявляется объектом последовательностиявляетсякоторый оценивает лениво.
Это верно, но в Python 3, .range()
будет реализован на Python 2 .xrange()
.Если вам действительно нужно сгенерировать список, вам нужно будет сделать:
list(range(1,100))
Помните, используйте 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()
в любом случае это даст вам хорошее поведение итератора.
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
но без ограничений на минимальные и максимальные конечные точки.
xrange возвращает итератор и одновременно сохраняет в памяти только одно число.диапазон сохраняет весь список чисел в памяти.
Проведите некоторое время с Ссылка на библиотеку.Чем лучше вы с этим знакомы, тем быстрее сможете найти ответы на подобные вопросы.Особенно важны первые несколько глав о встроенных объектах и типах.
Преимущество типа xrange заключается в том, что объект xrange всегда будет занимать одинаковый объем памяти, независимо от размера диапазона, который он представляет.Нет никаких постоянных преимуществ в производительности.
Другим способом быстрого поиска информации о конструкции Python является строка документации и справочная функция:
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
range создает список, поэтому, если вы используете range (1, 10000000), он создает список в памяти с 10000000 элементами.xrange - это генератор, поэтому он вычисляет лениво.
Это дает вам два преимущества:
- Вы можете перебирать более длинные списки, не получая
MemoryError
. - Поскольку он лениво разрешает каждое число, если вы остановите итерацию раньше, вы не будете тратить время на создание всего списка.
Я потрясен, что никто не читал док:
Эта функция очень похожа на
range()
, но возвращаетxrange
объект вместо списка.Это непрозрачный тип последовательности, который выдает те же значения, что и соответствующий список, фактически не сохраняя их все одновременно.Преимуществоxrange()
закончилсяrange()
является минимальным (посколькуxrange()
по-прежнему должен создавать значения, когда их запрашивают), за исключением случаев, когда на компьютере с нехваткой памяти используется очень большой диапазон или когда все элементы диапазона никогда не используются (например, когда цикл обычно завершаетсяbreak
).
Это делается по соображениям оптимизации.
range() создаст список значений от начала до конца (0 ..20 в вашем примере).Это станет дорогостоящей операцией на очень больших диапазонах.
с другой стороны, xrange() гораздо более оптимизирован.он будет вычислять следующее значение только при необходимости (через объект последовательности xrange) и не создает список всех значений, как это делает range().
Вы обнаружите преимущество 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
Счастливого Кодирования!!
диапазон (): диапазон (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
При использовании циклов нет большой разницы, хотя есть разница при простой печати!
В python 2.x
дальность действия (x) возвращает список, созданный в памяти из x элементов.
>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]
диапазон x(x) возвращает объект xrange, который является генератором obj, который генерирует числа по запросу.они вычисляются во время цикла for (отложенное вычисление).
Для зацикливания это немного быстрее, чем range(), и более эффективно использует память.
>>> b = xrange(5)
>>> b
xrange(5)
При тестировании range против xrange в цикле (я знаю, что должен использовать время пришло, но это было быстро вырезано из памяти с использованием простого примера понимания списка) Я нашел следующее:
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?
Или, используя xrange в цикле for:
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?Или лучший пример :-)
В некоторых других ответах упоминается, что Python 3 устранил 2.x range
и переименован в 2.x's xrange
Для range
.Однако, если вы не используете 3.0 или 3.1 (чего никому не следует делать), на самом деле это несколько другой тип.
Как документы 3.1 сказать:
Объекты диапазона имеют очень слабое поведение:они поддерживают только индексацию, итерацию и
len
функция.
Однако в 3.2+, range
является полной последовательностью — она поддерживает расширенные фрагменты и все методы collections.abc.Sequence
с той же семантикой, что и list
.*
И, по крайней мере, в CPython и PyPy (единственных двух существующих в настоящее время реализациях 3.2+), он также имеет реализации с постоянным временем index
и count
методы и in
оператор (при условии, что вы передаете ему только целые числа).Это означает написание 123456 in r
разумно в версии 3.2+, в то время как в версии 2.7 или 3.1 это было бы ужасной идеей.
* Тот факт , что issubclass(xrange, collections.Sequence)
ВОЗВРАТ True
в 2.6-2.7 и 3.0-3.1 это ошибка это было исправлено в версии 3.2 и не перенесено обратно.
xrange() и range() в python работают аналогично для пользователя, но разница возникает, когда мы говорим о том, как распределяется память при использовании обеих функций.
Когда мы используем range(), мы выделяем память для всех генерируемых им переменных, поэтому не рекомендуется использовать с большим номером.переменных, которые должны быть сгенерированы.
с другой стороны, xrange() генерирует только определенное значение за раз и может использоваться только с циклом for для печати всех необходимых значений.
range генерирует весь список и возвращает его.xrange этого не делает - он генерирует числа в списке по запросу.
Прочтите следующий пост для сравнения range и xrange с помощью графического анализа.
xrange использует итератор (генерирует значения "на лету"), range возвращает список.
Что?
range
возвращает статический список во время выполнения.
xrange
возвращает object
(который действует как генератор, хотя это, конечно, не таковой), из которого генерируются значения по мере необходимости.
Когда и что использовать?
- Использование
xrange
если вы хотите сгенерировать список для гигантского диапазона, скажем, для 1 миллиарда, особенно если у вас "чувствительная к памяти система", такая как сотовый телефон. - Использование
range
если вы хотите пройтись по списку несколько раз.
PS:Python 3.x's range
функция == Python 2.x's xrange
функция.
Что касается требований к сканированию / печати 0-N элементов, range и xrange работают следующим образом.
range() - создает новый список в памяти и берет от 0 до N элементов (всего N + 1) и печатает их.xrange() - создает экземпляр итератора, который сканирует элементы и сохраняет в памяти только текущий обнаруженный элемент, следовательно, постоянно использует один и тот же объем памяти.
Только в том случае, если требуемый элемент находится в начале списка, это значительно экономит время и память.
Разница уменьшается при меньших аргументах до range(..)
/ xrange(..)
:
$ python -m timeit "for i in xrange(10111):" " for k in range(100):" " pass"
10 loops, best of 3: 59.4 msec per loop
$ python -m timeit "for i in xrange(10111):" " for k in xrange(100):" " pass"
10 loops, best of 3: 46.9 msec per loop
В данном случае xrange(100)
это всего лишь примерно на 20% эффективнее.
Все прекрасно это объясняли.Но я хотел увидеть это своими глазами.Я использую python3.Итак, я открыл монитор ресурсов (в Windows!) и сначала выполнил следующую команду:
a=0
for i in range(1,100000):
a=a+i
а затем проверил изменение в используемой памяти.Это было несущественно.Затем я запустил следующий код:
for i in list(range(1,100000)):
a=a+i
И для этого мгновенно потребовался большой кусок памяти.И я был убежден.Вы можете попробовать это сами.
Если вы используете Python 2X, то замените 'range()' на 'xrange()' в первом коде и 'list(range())' на 'range()'.
Диапазон возвращает Список в то время как диапазон xrange возвращает диапазон xrange объект, который занимает одну и ту же память независимо от размера диапазона, поскольку в этом случае генерируется только один элемент и он доступен за итерацию, тогда как в случае использования диапазона все элементы генерируются одновременно и доступны в памяти.
диапазон: -диапазон заполнит все сразу.это означает, что каждое число диапазона будет занимать память.
xrange :-xrange что-то вроде генератора ,он входит в картину, когда вы хотите, чтобы данный диапазон чисел, но вы не хотите, чтобы они хранились,как, когда нужно использовать в цикле for.поэтому эффективная память.
Из справочных документов.
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
становится xrange
из Python 2.x, и xrange
удаляется.
Кроме того, если вы list(xrange(...))
будет эквивалентно range(...)
.
Итак list
идет медленно.
Также xrange
на самом деле это не полностью завершает последовательность
Так вот почему это не список, это xrange
объект
Видишь это Публикация чтобы найти разницу между range и xrange:
Процитировать:
range
возвращает именно то, что вы думаете:список последовательных целых чисел определенной длины, начинающихся с 0.xrange
, однако возвращает "объект xrange", который действует во многом как итератор