Ответы:
В Python 2.x:
range
создает список, поэтому, если вы это сделаете, range(1, 10000000)
он создает список в памяти с 9999999
элементами.
xrange
является объектом последовательности, который оценивает лениво.
В Python 3 range
делает эквивалент Python xrange
, и чтобы получить список, вы должны использовать list(range(...))
.
xrange(x).__iter__()
это генератор.
i
оценивается по требованию, а не при инициализации.
range создает список, поэтому, если вы это сделаете,
range(1, 10000000)
он создает список в памяти с9999999
элементами.
xrange
является генератором, так чтоэто объект последовательности,который оценивает лениво.
Это правда, но в Python 3 .range()
будет реализован Python 2 .xrange()
. Если вам нужно сгенерировать список, вам нужно сделать:
list(range(1,100))
xrange
генератора? Это функция, содержащая yield
оператор, и согласно глоссарию такие функции называются генераторами.
Помните, используйте 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()
любом случае даст вам хорошее поведение итератора.
python -m timeit "for i in xrange(1000000):" " pass"
the extra overhead is only 0.04 seconds
это неправильный взгляд на него, (90.5-51.1)/51.1 = 1.771 times slower
он правильный, поскольку он говорит о том, что, если это основной цикл вашей программы, он потенциально может стать узким местом. Однако, если это небольшая часть, то 1,77х - это немного.
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
ничего не возвращает итератор.
and only keeps one number in memory at a time
и где остальные размещены, пожалуйста,
Потратьте некоторое время на Библиотечный справочник . Чем более вы знакомы с ним, тем быстрее вы сможете найти ответы на подобные вопросы. Особенно важны первые несколько глав о встроенных объектах и типах.
Преимущество типа xrange заключается в том, что объект xrange всегда будет занимать одинаковый объем памяти, независимо от размера диапазона, который он представляет. Там нет последовательных преимуществ производительности.
Другой способ найти быструю информацию о конструкции Python - это строка документации и функция справки:
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
Я в шоке, никто не читал док :
Эта функция очень похожа
range()
, но возвращает списокxrange
вместо списка. Это непрозрачный тип последовательности, который выдает те же значения, что и соответствующий список, фактически не сохраняя их все одновременно. Преимуществоxrange()
overrange()
минимально (посколькуxrange()
все еще нужно создавать значения, когда их запрашивают), за исключением случаев, когда на машине с нехваткой памяти используется очень большой диапазон или когда все элементы диапазона никогда не используются (например, когда цикл обычно заканчивается сbreak
).
range создает список, поэтому, если вы сделаете range (1, 10000000), он создаст список в памяти с 10000000 элементов. xrange - генератор, поэтому он оценивает лениво.
Это дает вам два преимущества:
MemoryError
.Вы найдете преимущество 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 они покончили с этим.
Удачного кодирования!
Это из соображений оптимизации.
range () создаст список значений от начала до конца (0 .. 20 в вашем примере). Это станет дорогой операцией на очень больших диапазонах.
С другой стороны, xrange () гораздо более оптимизирован. он будет вычислять следующее значение только при необходимости (через объект последовательности xrange) и не будет создавать список всех значений, таких как range ().
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
При использовании петель нет большой разницы, хотя есть разница только при печати!
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__
xrange([start,] stop[, step]) -> xrange object
В некоторых других ответах упоминается, что Python 3 исключил 2.x range
и переименовал 2.x xrange
в range
. Однако, если вы не используете 3.0 или 3.1 (что никто не должен делать), это на самом деле несколько другой тип.
Как сказано в документах 3.1 :
Объекты Range имеют очень небольшое поведение: они поддерживают только индексацию, итерацию и
len
функцию.
Тем не менее, в 3.2+, range
это полная последовательность - она поддерживает расширенные слайсы и все методы collections.abc.Sequence
с той же семантикой, что и a 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 и не портирована.
В Python 2.x
range (x) возвращает список, созданный в памяти с x элементами.
>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]
xrange (x) возвращает объект xrange, который является генератором obj, который генерирует числа по требованию. они вычисляются во время цикла for (Lazy Evaluation).
Для цикла это немного быстрее, чем range () и более эффективно использовать память.
>>> b = xrange(5)
>>> b
xrange(5)
xrange()
не генератор xrange(n)
.__ iter __ () `есть.
При тестировании диапазона против xrange в цикле (я знаю, что должен использовать timeit , но это было быстро взломано из памяти с помощью простого примера понимания списка), я обнаружил следующее:
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? Или лучший пример :-)
xrange
выглядел немного быстрее, хотя с Python 3 сравнение теперь излишне.
timeit
. Он многократно работает, отключает GC, использует лучшие часы вместо time
и т. Д.
xrange () и range () в python работают так же, как и для пользователя, но разница возникает, когда мы говорим о том, как распределяется память при использовании обеих функций.
Когда мы используем range (), мы выделяем память для всех переменных, которые он генерирует, поэтому не рекомендуется использовать с большим значением no. переменных, которые будут сгенерированы.
xrange (), с другой стороны, генерирует только определенное значение за раз и может использоваться только с циклом for для печати всех требуемых значений.
Какая?
range
возвращает статический список во время выполнения.
xrange
возвращает object
(который действует как генератор, хотя, конечно, не один), из которого генерируются значения, как и когда это необходимо.
Когда использовать что?
xrange
если вы хотите создать список для гигантского диапазона, скажем, 1 миллиард, особенно если у вас есть «чувствительная к памяти система», такая как мобильный телефон.range
если вы хотите перебрать список несколько раз.PS: Python 3.x в range
функции == Python 2.x в xrange
функции.
xrange
не возвращает объект генератора.
Все это очень хорошо объяснили. Но я хотел увидеть это сам. Я использую 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 ().
С помощью документов.
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
удаляется.
По требованию к сканированию / печати 0-N предметов, range и xrange работает следующим образом.
range () - создает новый список в памяти, принимает от 0 до N элементов (всего N + 1) и печатает их. xrange () - создает экземпляр итератора, который просматривает элементы и сохраняет в памяти только текущий обнаруженный элемент, следовательно, все время используя один и тот же объем памяти.
Если требуемый элемент находится в начале списка только тогда, он экономит много времени и памяти.
xrange
не создает экземпляр итератора. Он создает xrange
объект, который является итеративным, но не итератором, почти (но не совсем) последовательностью, подобной списку.
Range возвращает список, в то время как xrange возвращает объект 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% эффективнее.
range: -range заполнит все сразу. Это означает, что каждое число диапазона будет занимать память.
xrange: -xrange - это что-то вроде генератора, он появляется, когда вы хотите диапазон чисел, но вы не хотите, чтобы они были сохранены, например, когда вы хотите использовать эффективную память для loop.so.
Кроме того, если сделать list(xrange(...))
будет эквивалентно range(...)
.
Так list
медленно.
Также на xrange
самом деле не полностью закончить последовательность
Так вот почему это не список, это xrange
объект
range()
в Python 2.x
Эта функция по сути является старой range()
функцией, которая была доступна в Python, 2.x
и возвращает экземпляр list
объекта, который содержит элементы в указанном диапазоне.
Однако эта реализация слишком неэффективна, когда речь идет об инициализации списка с диапазоном чисел. Например, for i in range(1000000)
это будет очень дорогая команда для выполнения, как с точки зрения использования памяти, так и времени, так как она требует сохранения этого списка в памяти.
range()
в Python 3.x
и xrange()
в Python2.x
Python 3.x
представил более новую реализацию range()
(в то время как более новая реализация уже была доступна в Python 2.x
через xrange()
функцию).
Эксплуатирует range()
стратегию, известную как ленивая оценка. Вместо создания огромного списка элементов в диапазоне, более новая реализация представляет класс range
, легкий объект, который представляет требуемые элементы в данном диапазоне, не сохраняя их явно в памяти (это может звучать как генераторы, но концепция ленивых вычислений заключается в том, что другой).
В качестве примера рассмотрим следующее:
# Python 2.x
>>> a = range(10)
>>> type(a)
<type 'list'>
>>> b = xrange(10)
>>> type(b)
<type 'xrange'>
а также
# Python 3.x
>>> a = range(10)
>>> type(a)
<class 'range'>
Смотрите этот пост, чтобы найти разницу между range и xrange:
Цитировать:
range
возвращает именно то, что вы думаете: список последовательных целых чисел определенной длины, начинающихся с 0.xrange
Однако возвращает «объект xrange» , который очень похож на итератор
xrange
не является итератором. Список, возвращаемый range
функцией действительно поддерживает итерацию (список является в значительной степени прототипом примера итерации). Общая выгода xrange
не является "минимальной". И так далее.