По-видимому, xrange быстрее, но я понятия не имею, почему он быстрее (и пока нет доказательств, кроме анекдотического, что он быстрее) или что, кроме этого, отличается
for i in range(0, 20):
for i in xrange(0, 20):






См. Этот почтовый, чтобы найти разницу между диапазоном и xrange:
Цитировать:
rangereturns exactly what you think: a list of consecutive integers, of a defined length beginning with 0.xrange, however, returns an "xrange object", which acts a great deal like an iterator
xrange возвращает итератор и сохраняет в памяти только одно число. range сохраняет в памяти весь список чисел.
xrange возвращает нет итератор.
and only keeps one number in memory at a time, а где размещены остальные, пожалуйста, помогите мне.
@SIslam Если он знает начало, конец и текущее, он может вычислить следующее, по одному.
В Python 2.x:
range создает список, поэтому, если вы выполняете range(1, 10000000), он создает список в памяти с элементами 9999999.
xrange - это объект последовательности, который выполняет ленивую оценку.
В Python 3:
range является эквивалентом xrange в Python 2. Чтобы получить список, вы должны явно использовать list(range(...)).xrange больше не существует.xrange - это не совсем генератор, но он лениво вычисляет и действует как генератор.
xrange(x).__iter__() - это генератор.
Почему они сделали xrange вместо того, чтобы ленить range?
@RobertGrant Если вы перебираете этот список 1000 раз, будет медленнее генерировать значения каждый раз
@RobertGrant, они сделали. В Python 3. (Они не могли этого сделать в строке Python 2.x, поскольку все изменения должны быть обратно совместимы.)
Может кто-нибудь объяснить, что означает «лениво оценивает»? Спасибо!
@Ratul означает, что каждый i оценивается по запросу, а не при инициализации.
xrange - это итератор, который лениво вычисляет? Вызов метода iter() на xrange возвращает генератор?
Обратите внимание, это относится только к Python2. Поскольку Python3 не имеет «xrange», его функция «range» будет работать как xrange в Python2.
@DarshanChaudhary: xrange - это повторяемый (с последовательным поведением), который оценивает лениво, а не итератор. Вызов iter() на нем создает итератор (который люди вольно называют генератором, хотя в Python «генератор» - это особый тип итератора, созданный с помощью выражения генератора или функции, использующей ключевое слово yield, ни одно из которых на самом деле не применимо к xrange).
range генерирует весь список и возвращает его. xrange этого не делает - он генерирует числа в списке по запросу.
xrange использует итератор (генерирует значения на лету), range возвращает список.
Проведите некоторое время с Справочная библиотека. Чем больше вы с ним знакомы, тем быстрее сможете найти ответы на подобные вопросы. Особенно важны первые несколько глав о встроенных объектах и типах.
The advantage of the xrange type is that an xrange object will always take the same amount of memory, no matter the size of the range it represents. There are no consistent performance advantages.
Еще один способ быстро найти информацию о конструкции Python - это строка документации и справочная функция:
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
Библиотека хороша, но не всегда так просто получить ответ на интересующий вас вопрос.
Перейдите к ссылке на библиотеку, нажмите ctrl + f, найдите диапазон, и вы получите два результата. Найти ответ на этот вопрос не так уж и сложно.
Ссылка на библиотеку не работает. Не могли бы вы обновить его?
Это сделано из соображений оптимизации.
range () создаст список значений от начала до конца (0 .. 20 в вашем примере). Это станет дорогостоящей операцией на очень больших диапазонах.
xrange () с другой стороны, намного более оптимизирован. он будет вычислять следующее значение только при необходимости (через объект последовательности xrange) и не создает список всех значений, как это делает range ().
range creates a list, so if you do
range(1, 10000000)it creates a list in memory with9999999elements.
xrangeis a generator, so itis a sequence objectis athat evaluates lazily.
Это правда, но в Python 3 range() будет реализован в Python 2 xrange(). Если вам действительно нужно сгенерировать список, вам нужно будет сделать:
list(range(1,100))
Я не вижу в этом большой проблемы (с точки зрения нарушения работы существующих приложений), поскольку диапазон был в основном для генерации индексов, которые будут использоваться в циклах for как «for i in range (1, 10):
+1 Спасибо за этот ответ, информация о замене Python 3 range на xrange очень полезна. Я на самом деле сказал кому-то использовать xrange или range, и они сказали, что это не имеет значения в python 3, поэтому я искал в Google дополнительную информацию, и этот ответ пришел :)
Что плохого в том, чтобы называть xrange генератором? Это функция, содержащая оператор yield, и в соответствии с глоссарий такие функции называются генераторами.
@winterlight, думаю, правильный термин для этого - итератор. Генераторы тоже должны иметь возможность получать.
@McSinyx - winterlight правильно, что функция, возвращающая генератор, также называется генератором. Объект-генератор - это частный случай итератора. См. генераторы против итераторов.
@scign, см. PEP 342 для канонического определения протокола генератора. Хороший итог можно найти в документация по аннотации типов (они имеют псевдоним typing.*).
@McSinyx рад, что вы согласны.
Нет, @scign. Вы читали связанный PEP и документ? В прошлом эти два термина могли использоваться как взаимозаменяемые, но на момент написания генераторы должны иметь возможность получать значения. Кроме того, диапазон Python 3 также не является итератором (попробуйте next(range(42))).
xrange сохраняет только параметры диапазона и генерирует числа по запросу. Однако реализация Python на C в настоящее время ограничивает свои аргументы значениями C long:
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, и он ведет себя как xrange 2.x, но без ограничений на минимальные и максимальные конечные точки.
range creates a list, so if you do range(1, 10000000) it creates a list in memory with 10000000 elements. xrange is a generator, so it evaluates lazily.
Это дает вам два преимущества:
MemoryError.Помните, используйте модуль 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() все равно даст вам хорошее поведение итератора.
+1 для примера timeit. Примечание: для запуска в windows cmd необходимо использовать двойные кавычки, т.е. ". Таким образом, код будет python -m timeit "for i in xrange(1000000):" " pass".
Основное преимущество xrange - это память, а не время.
+1 за практический ответ: использовать диапазон, если он не огромен. Кстати, они концептуально идентичны, верно? Как ни странно, нет ответа на этот вопрос.
Если xrange быстрее и не забирает память, зачем вообще использовать диапазон?
Я в целом согласен с вашим утверждением, но ваша оценка неверна: the extra overhead is only 0.04 seconds - неправильный способ взглянуть на него, (90.5-51.1)/51.1 = 1.771 times slower правильный, потому что он передает, что, если это основной цикл вашей программы, он потенциально может стать узким местом. Однако, если это небольшая часть, то 1,77x - это немного.
Это плохой совет. На самом деле единственным преимуществом range является то, что у вас есть какое-то эстетическое мнение о том, что он менее уродлив для чтения, чем xrange, или если вам действительно нужен list. Кроме того, выполнение timeit на вашем компьютере, скорее всего, не будет напоминать среду, в которой будет выполняться ваш код, и ничего не скажет вам о последствиях для памяти.
При тестировании диапазона против 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? Или лучший пример :-)
Одноразовое выполнение такого теста не дает точных результатов по времени. Всегда есть отклонения .. Это может быть либо сборщик мусора, либо другой процесс, ворующий ЦП ... что угодно. Вот почему тесты обычно проводятся 10-100-1000 -...
это всего лишь поспешная распечатка фрагмента - я запускал его несколько раз, но только до 100, и xrange казался немного быстрее, хотя с Python 3 сравнение теперь излишне.
Для этого и предназначен timeit. Он заботится о многократном запуске, отключении GC, использовании лучших часов вместо time и т. д.
По требованию для сканирования / печати элементов 0-N, range и xrange работают следующим образом.
range () - создает новый список в памяти, принимает все элементы от 0 до N (всего N + 1) и печатает их. xrange () - создает экземпляр итератора, который просматривает элементы и сохраняет в памяти только текущий встреченный элемент, поэтому все время использует один и тот же объем памяти.
В том случае, если требуемый элемент находится только в начале списка, это позволяет сэкономить много времени и памяти.
xrange не создает экземпляр итератора. Он создает объект xrange, который является итеративным, но не итератором - почти (но не совсем) последовательность, например список.
Я в шоке, что никто не читал док:
This function is very similar to
range(), but returns anxrangeobject instead of a list. This is an opaque sequence type which yields the same values as the corresponding list, without actually storing them all simultaneously. The advantage ofxrange()overrange()is minimal (sincexrange()still has to create the values when asked for them) except when a very large range is used on a memory-starved machine or when all of the range’s elements are never used (such as when the loop is usually terminated withbreak).
Что? range возвращает статический список во время выполнения.
xrange возвращает object (который действует как генератор, хотя, конечно, не один), из которого значения генерируются по мере необходимости.
Когда какой использовать?
xrange, если вы хотите создать список для гигантского диапазона, скажем, 1 миллиарда, особенно когда у вас есть «система, чувствительная к памяти», такая как сотовый телефон.range, если вы хотите перебрать список несколько раз.PS: функция range Python 3.x == функция xrange Python 2.x.
xrange не возвращает объект-генератор.
Если я правильно понимаю, вот как это объясняется здесь (для Python 2.x): wiki.python.org/moin/Generators
Тогда вики ошибается. (Я не знаю, кто такая «SH», кто добавил и подписал этот комментарий.) Официальная документация прав; вы можете проверить это сами и посмотреть, генератор это или последовательность.
Ok. Но это все еще сбивает с толку после прочтения этого: stackoverflow.com/questions/135041/…
Если вы прочитаете даже первое предложение этого комментария, в нем говорится: «xrange(1000) - это объект, который действует как генератор (хотя это, конечно, не один)». (выделено мной) Но даже если не сделал так говорит, собираетесь ли вы доверять одноразовому комментарию случайного пользователя SO по официальной документации Python или тому, что вы можете увидеть, протестировав его самостоятельно?
Во всяком случае, он вообще не действует как генератор. Последовательность - это вещь, которую можно повторять многократно, потому что ее __iter__ возвращает новый объект, и ее можно индексировать, потому что у нее есть __getitem__, и так далее. Генератор - это то, что потребляется при повторении, потому что его __iter__ возвращает self, и он не может быть проиндексирован, и он содержит фрейм приостановленного стека, и у него есть методы send и throw. На какой из них звучит xrange?
Интересный вопрос: что делать, если интерпретатор не согласен с официальной документацией или с другим переводчиком… Но, к счастью, это возникает не слишком часто…
Классифицировать возвращает список, в то время как xrange возвращает объект xrange, который занимает ту же память независимо от размера диапазона, так как в этом случае только один элемент создается и доступен на итерацию, тогда как в случае использования диапазона все элементы создаются одновременно и доступны в памяти.
В некоторых других ответах упоминается, что Python 3 устранил range из 2.x и переименовал xrange из 2.x в range. Однако, если вы не используете 3.0 или 3.1 (что никому не должно быть), на самом деле это несколько другой тип.
Как говорит документы 3.1:
Range objects have very little behavior: they only support indexing, iteration, and the
lenfunction.
Однако в версии 3.2+ range представляет собой полную последовательность - он поддерживает расширенные срезы и все методы collections.abc.Sequence с той же семантикой, что и list.*.
И, по крайней мере, в CPython и PyPy (единственные две реализации 3.2+, которые в настоящее время существуют), он также имеет реализации с постоянным временем методов index и count и оператора in (при условии, что вы передаете ему только целые числа). Это означает, что написание 123456 in r в версии 3.2+ разумно, а в версии 2.7 или 3.1 было бы ужасной идеей.
* The fact that issubclass(xrange, collections.Sequence) returns True in 2.6-2.7 and 3.0-3.1 is a bug that was fixed in 3.2 and not backported.
Разница уменьшается для меньших аргументов для 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 (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
xrange () и range () в python работают так же, как и для пользователя, но разница возникает, когда мы говорим о том, как распределяется память при использовании обеих функций.
Когда мы используем range (), мы выделяем память для всех генерируемых переменных, поэтому не рекомендуется использовать с большим номером. переменных, которые будут сгенерированы.
С другой стороны, xrange () генерирует только определенное значение за раз и может использоваться только с циклом for для печати всех требуемых значений.
В python 2.x
диапазон (x) возвращает список, созданный в памяти с элементами x.
>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]
xrange (x) возвращает объект xrange, который является генератором obj, который генерирует числа по запросу. они вычисляются во время цикла for (ленивая оценка).
Для цикла это немного быстрее, чем range (), и более эффективно использует память.
>>> b = xrange(5)
>>> b
xrange(5)
xrange() не является генератором. xrange(n) .__ iter __ () `есть.
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
Нет особой разницы при использовании циклов, хотя есть разница при простой печати!
Вы увидите преимущество 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: -range заполнит все сразу. это означает, что каждое число диапазона будет занимать память.
xrange: -xrange - это что-то вроде генератора, он появится, когда вам нужен диапазон чисел, но вы не хотите, чтобы они сохранялись, например, когда вы хотите использовать in for loop.so эффективно использовать память.
Все это очень хорошо объяснили. Но я хотел убедиться в этом сам. Я использую 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 ().
Из справки docs.
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(), которая была доступна в Python 2.x и возвращает экземпляр объекта list, который содержит элементы в указанном диапазоне.
Однако эта реализация слишком неэффективна, когда дело доходит до инициализации списка с диапазоном чисел. Например, for i in range(1000000) будет очень дорогостоящей командой для выполнения как с точки зрения использования памяти, так и с точки зрения использования времени, поскольку для этого требуется сохранение этого списка в памяти.
range() в Python 3.x и xrange() в Python 2.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'>
Я понимаю, что ему 5 лет, но этот пост неверен почти во всем.
xrangeне является итератором. Список, возвращаемыйrange, поддерживает итерацию (список в значительной степени является прототипом итерации). Общее преимуществоxrangeне является «минимальным». И так далее.