Может кто-нибудь кратко описать разницу между двумя для нас, не питонов, ребят? Может быть, что-то вроде «xrange () выполняет все функции range (), но также поддерживает X, Y и Z»
Outlaw Programmer
87
range (n) создает список, содержащий все целые числа 0..n-1. Это проблема, если вы делаете диапазон (1000000), потому что в итоге вы получите список> 4Mb. xrange справляется с этим, возвращая объект, который претендует на то, чтобы быть списком, но просто вычисляет необходимое число из запрошенного индекса и возвращает его.
По сути, тогда range(1000)как a list, xrange(1000)это объект, который действует как a generator(хотя это, безусловно, не один). Кроме того, xrangeбыстрее. Вы можете import timeit from timeitи затем создать метод, который просто имеет for i in xrange: passи другой для range, затем сделать timeit(method1)и timeit(method2), и, о чудо, xrange иногда почти в два раза быстрее (то есть, когда вам не нужен список). (Для меня, для i in xrange(1000):passvs for i in range(1000):passпотребовалось 13.316725969314575vs 21.190124988555908секунд соответственно - это много.)
Для производительности, особенно когда вы выполняете итерации в большом диапазоне, 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 или в понимании, или там, где уже заключен в list (), диапазон остается неизменным.
Что вы подразумеваете под "диапазон станет итератором"? Разве это не должно быть "генератором"?
Майкл Миор
4
Нет. Генератор относится к конкретному типу итератора, а новый rangeв любом случае не является итератором.
user2357112 поддерживает Monica
Твоя вторая пуля не имеет никакого смысла. Вы говорите, что не можете использовать объект несколько раз; что вы можете! попробуйте xr = xrange(1,11)потом на следующей строке for i in xr: print " ".join(format(i*j,"3d") for j in xr)и вуаля! У вас есть расписание до десяти. Он работает так же, как r = range(1,11)и for i in r: print " ".join(format(i*j,"3d") for j in r)... все это объект в Python2. Я думаю, что вы хотели сказать, так это то, что вы можете лучше использовать индексное понимание (если это имеет смысл) rangeв отличие от xrange. Я думаю, что диапазон удобен очень редко
dylnmc
(Не хватает места) Хотя, я делать думаю , что rangeможет быть удобно , если вы хотите использовать listв цикле , а затем изменить некоторые показатели , основанные на определенных условиях или дописать вещей в этом списке, то range, безусловно , лучше. Тем не менее, xrangeон просто быстрее и использует меньше памяти, поэтому для большинства циклических приложений он кажется лучшим. Есть случаи - возвращаясь к вопросу спрашивающего - редко, но существуют, где rangeбыло бы лучше. Возможно, не так редко, как я думаю, но я, безусловно, использую xrange95% времени.
2011 года
129
Нет, у них обоих есть свои применения:
Используйте 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
Вы должны способствовать range()более xrange()только тогда , когда вам нужен фактический список. Например, когда вы хотите изменить список, возвращенный range()или когда вы хотите нарезать его. Для итерации или даже просто нормального индексирования xrange()будет работать нормально (и, как правило, гораздо эффективнее). Есть момент, когда range()он немного быстрее, чем xrange()для очень маленьких списков, но в зависимости от вашего оборудования и различных других деталей, безубыточность может быть результатом длины 1 или 2; не о чем беспокоиться. Предпочитают xrange().
Еще одно отличие состоит в том, что xrange () не может поддерживать числа больше C, поэтому, если вы хотите иметь диапазон с использованием встроенной поддержки больших чисел в Python, вы должны использовать range ().
Python2.7.3(default,Jul132012,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 не имеет этой проблемы:
Python3.2.3(default,Jul142012,01:01:48)[GCC 4.7.1] on linux2
Type"help","copyright","credits"or"license"for more information.>>> range(123456787676676767676676,123456787676676767676679)
range(123456787676676767676676,123456787676676767676679)
xrange()более эффективен, потому что вместо генерации списка объектов, он просто генерирует один объект за раз. Вместо 100 целых чисел, всех их накладных расходов и списка, в который они помещаются, у вас есть только одно целое число за раз. Более быстрое поколение, лучшее использование памяти, более эффективный код.
Если мне не нужен какой-то список, я всегда одобряю xrange()
range () возвращает список, xrange () возвращает объект xrange.
xrange () немного быстрее и эффективнее с точки зрения памяти. Но выигрыш не очень большой.
Дополнительная память, используемая списком, конечно, не просто тратится впустую, списки обладают большей функциональностью (слайс, повтор, вставка, ...). Точные различия можно найти в документации . Там нет правила костей, используйте то, что нужно.
Python 3.0 все еще находится в разработке, но IIRC range () будет очень похож на xrange () из 2.X, а list (range ()) может использоваться для генерации списков.
Я просто хотел бы сказать, что ДЕЙСТВИТЕЛЬНО не так сложно получить объект xrange с функциями слайса и индексации. Я написал некоторый код, который работает довольно хорошо и так же быстро, как xrange, когда он считается (итерации).
from __future__ import division
def read_xrange(xrange_object):# returns the xrange object's 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
classXrange(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 objectsif 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,Noneif 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:raiseValueError(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 !=Noneelse0# convert start = None to start = 0if start <0:
start += start
start = self[start]if start <0:raiseIndexError(item)
step =(self.step if self.step !=Noneelse1)*(step if step !=Noneelse1)
stop = stop if stop isnotNoneelse self.xrange[-1]if stop <0:
stop += stop
stop = self[stop]
stop = stop
if stop > self.stop:raiseIndexErrorif start < self.start:raiseIndexErrorreturnXrange(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 все равно должен делать все это ...
Да, согласился; из совершенно другой технологии, проверьте работу над lodash, чтобы сделать ее ленивой: github.com/lodash/lodash/issues/274 . Нарезка и т. Д. Все еще должна быть как можно более ленивой, а где - нет, только тогда тушить.
Роб Грант
4
Хороший пример, приведенный в книге: Практический Питон Магнус Ли Хетланд
Я не рекомендовал бы использовать диапазон вместо xrange в предыдущем примере - хотя необходимы только первые пять чисел, range вычисляет все числа, и это может занять много времени. С xrange это не проблема, потому что он вычисляет только те числа, которые нужны.
Да, я прочитал ответ @ Brian: в python 3 range () в любом случае является генератором, а xrange () не существует.
Не делай этого. xrange () уйдет, но и многое другое. Инструмент, который вы будете использовать для перевода вашего кода Python 2.x в код Python 3.x, автоматически переведет xrange () в range (), но range () будет переведен в менее эффективный список (range ()).
Томас Воутерс
10
Томас: На самом деле это немного умнее, чем это. Он переведет range () в ситуациях, когда ему явно не нужен реальный список (например, в цикле for или в понимании), просто в range (). Только те случаи, когда она присваивается переменной или используется напрямую, должна быть заключена в list ()
Brian
2
Ладно, у всех здесь другое мнение относительно компромиссов и преимуществ xrange по сравнению с диапазоном. Они в основном правильные, xrange - итератор, а диапазон расширяется и создает реальный список. В большинстве случаев вы не заметите разницу между ними. (Вы можете использовать карту с диапазоном, но не с xrange, но он использует больше памяти.)
Однако я думаю, что вы хотите услышать, что предпочтительным вариантом является xrange. Поскольку range в Python 3 является итератором, инструмент преобразования кода 2to3 правильно преобразует все варианты использования xrange в range и выдает ошибку или предупреждение при использовании range. Если вы хотите в будущем легко конвертировать код, вы будете использовать только xrange и list (xrange), когда уверены, что хотите получить список. Я узнал об этом во время спринта CPython на PyCon в этом году (2008) в Чикаго.
Это не правда. Код типа «для x в диапазоне (20)» будет оставлен как диапазон, а код типа «x = range (20)» будет преобразован в «x = list (range (20))» - без ошибок. Кроме того, если вы хотите написать код, который будет работать как в версии 2.6, так и в версии 3.0, range () - ваш единственный вариант без добавления функций совместимости.
Брайан
2
range(): range(1, 10) возвращает список от 1 до 10 номеров и сохраняет весь список в памяти.
xrange(): Нравится range(), но вместо возврата списка возвращает объект, который генерирует числа в диапазоне по требованию. Для циклов это немного быстрее range()и эффективнее с точки зрения памяти. xrange()Объект похож на итератор и генерирует числа по требованию (Lazy Evaluation).
range() делает то же самое, что и xrange() и в Python 3, и в Python 3 термин не xrange()существует. В некоторых случаях это
range()может быть быстрее, если вы повторяете одну и ту же последовательность несколько раз. xrange()должен восстанавливать целочисленный объект каждый раз, но range()будет иметь реальные целочисленные объекты.
Хотя xrangeэто быстрее, чем rangeв большинстве случаев, разница в производительности довольно минимальна. Маленькая программа ниже сравнивает итерации по a rangeи an 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 resultprint"Loop list of len %d: range=%.4f, xrange=%.4f"%(list_len, rtime, xrtime)
Результаты, приведенные ниже, показывают, что xrangeэто действительно быстрее, но недостаточно, чтобы потеть.
Loop list of len 1: range=0.0003, xrange=0.0003Loop list of len 10: range=0.0013, xrange=0.0011Loop list of len 100: range=0.0068, xrange=0.0034Loop list of len 1000: range=0.0609, xrange=0.0438Loop list of len 10000: range=0.5527, xrange=0.5266Loop list of len 100000: range=10.1666, xrange=7.8481Loop list of len 1000000: range=168.3425, xrange=155.8719
Так что во что бы то ни стало используйте xrange, но если вы не на ограниченном оборудовании, не беспокойтесь об этом.
range(1000)
как alist
,xrange(1000)
это объект, который действует как agenerator
(хотя это, безусловно, не один). Кроме того,xrange
быстрее. Вы можетеimport timeit from timeit
и затем создать метод, который просто имеетfor i in xrange: pass
и другой дляrange
, затем сделатьtimeit(method1)
иtimeit(method2)
, и, о чудо, xrange иногда почти в два раза быстрее (то есть, когда вам не нужен список). (Для меня, дляi in xrange(1000):pass
vs fori in range(1000):pass
потребовалось13.316725969314575
vs21.190124988555908
секунд соответственно - это много.)xrange(100)
на 20% быстрее, чемrange(100)
.Ответы:
Для производительности, особенно когда вы выполняете итерации в большом диапазоне,
xrange()
обычно лучше. Тем не менее, есть еще несколько случаев, по которым вы можете предпочестьrange()
:В Python 3
range()
делает то , чтоxrange()
раньше делал иxrange()
не существует. Если вы хотите написать код, который будет работать как на Python 2, так и на Python 3, вы не сможете его использоватьxrange()
.range()
на самом деле может быть быстрее в некоторых случаях - например. если итерация по одной и той же последовательности несколько раз.xrange()
должен восстанавливать целочисленный объект каждый раз, ноrange()
будет иметь реальные целочисленные объекты. (Это всегда будет работать хуже с точки зрения памяти, однако)xrange()
не используется во всех случаях, когда нужен реальный список. Например, он не поддерживает слайсы или любые методы списка.[Редактировать] Есть пара постов, в которых рассказывается, как
range()
будет обновляться с помощью инструмента 2to3. Для справки, вот результат запуска инструмента на некоторых примерах использованияrange()
иxrange()
Как вы можете видеть, при использовании в цикле for или в понимании, или там, где уже заключен в list (), диапазон остается неизменным.
источник
range
в любом случае не является итератором.xr = xrange(1,11)
потом на следующей строкеfor i in xr: print " ".join(format(i*j,"3d") for j in xr)
и вуаля! У вас есть расписание до десяти. Он работает так же, какr = range(1,11)
иfor i in r: print " ".join(format(i*j,"3d") for j in r)
... все это объект в Python2. Я думаю, что вы хотели сказать, так это то, что вы можете лучше использовать индексное понимание (если это имеет смысл)range
в отличие отxrange
. Я думаю, что диапазон удобен очень редкоrange
может быть удобно , если вы хотите использоватьlist
в цикле , а затем изменить некоторые показатели , основанные на определенных условиях или дописать вещей в этом списке, тоrange
, безусловно , лучше. Тем не менее,xrange
он просто быстрее и использует меньше памяти, поэтому для большинства циклических приложений он кажется лучшим. Есть случаи - возвращаясь к вопросу спрашивающего - редко, но существуют, гдеrange
было бы лучше. Возможно, не так редко, как я думаю, но я, безусловно, используюxrange
95% времени.Нет, у них обоих есть свои применения:
Используйте
xrange()
при итерации, так как это экономит память. Сказать:скорее, чем:
С другой стороны, используйте,
range()
если вы действительно хотите список чисел.источник
Вы должны способствовать
range()
болееxrange()
только тогда , когда вам нужен фактический список. Например, когда вы хотите изменить список, возвращенныйrange()
или когда вы хотите нарезать его. Для итерации или даже просто нормального индексированияxrange()
будет работать нормально (и, как правило, гораздо эффективнее). Есть момент, когдаrange()
он немного быстрее, чемxrange()
для очень маленьких списков, но в зависимости от вашего оборудования и различных других деталей, безубыточность может быть результатом длины 1 или 2; не о чем беспокоиться. Предпочитаютxrange()
.источник
Еще одно отличие состоит в том, что xrange () не может поддерживать числа больше C, поэтому, если вы хотите иметь диапазон с использованием встроенной поддержки больших чисел в Python, вы должны использовать range ().
Python 3 не имеет этой проблемы:
источник
xrange()
более эффективен, потому что вместо генерации списка объектов, он просто генерирует один объект за раз. Вместо 100 целых чисел, всех их накладных расходов и списка, в который они помещаются, у вас есть только одно целое число за раз. Более быстрое поколение, лучшее использование памяти, более эффективный код.Если мне не нужен какой-то список, я всегда одобряю
xrange()
источник
range () возвращает список, xrange () возвращает объект xrange.
xrange () немного быстрее и эффективнее с точки зрения памяти. Но выигрыш не очень большой.
Дополнительная память, используемая списком, конечно, не просто тратится впустую, списки обладают большей функциональностью (слайс, повтор, вставка, ...). Точные различия можно найти в документации . Там нет правила костей, используйте то, что нужно.
Python 3.0 все еще находится в разработке, но IIRC range () будет очень похож на xrange () из 2.X, а list (range ()) может использоваться для генерации списков.
источник
Я просто хотел бы сказать, что ДЕЙСТВИТЕЛЬНО не так сложно получить объект xrange с функциями слайса и индексации. Я написал некоторый код, который работает довольно хорошо и так же быстро, как xrange, когда он считается (итерации).
Честно говоря, я думаю, что вся эта проблема довольно глупа, и Xrange все равно должен делать все это ...
источник
Хороший пример, приведенный в книге: Практический Питон Магнус Ли Хетланд
Я не рекомендовал бы использовать диапазон вместо xrange в предыдущем примере - хотя необходимы только первые пять чисел, range вычисляет все числа, и это может занять много времени. С xrange это не проблема, потому что он вычисляет только те числа, которые нужны.
Да, я прочитал ответ @ Brian: в python 3 range () в любом случае является генератором, а xrange () не существует.
источник
Выберите диапазон по этим причинам:
1) xrange будет уходить в новых версиях Python. Это дает вам легкую совместимость в будущем.
2) диапазон возьмет на себя эффективность, связанную с xrange.
источник
Ладно, у всех здесь другое мнение относительно компромиссов и преимуществ xrange по сравнению с диапазоном. Они в основном правильные, xrange - итератор, а диапазон расширяется и создает реальный список. В большинстве случаев вы не заметите разницу между ними. (Вы можете использовать карту с диапазоном, но не с xrange, но он использует больше памяти.)
Однако я думаю, что вы хотите услышать, что предпочтительным вариантом является xrange. Поскольку range в Python 3 является итератором, инструмент преобразования кода 2to3 правильно преобразует все варианты использования xrange в range и выдает ошибку или предупреждение при использовании range. Если вы хотите в будущем легко конвертировать код, вы будете использовать только xrange и list (xrange), когда уверены, что хотите получить список. Я узнал об этом во время спринта CPython на PyCon в этом году (2008) в Чикаго.
источник
range()
:range(1, 10)
возвращает список от 1 до 10 номеров и сохраняет весь список в памяти.xrange()
: Нравитсяrange()
, но вместо возврата списка возвращает объект, который генерирует числа в диапазоне по требованию. Для циклов это немного быстрееrange()
и эффективнее с точки зрения памяти.xrange()
Объект похож на итератор и генерирует числа по требованию (Lazy Evaluation).range()
делает то же самое, что иxrange()
и в Python 3, и в Python 3 термин неxrange()
существует. В некоторых случаях этоrange()
может быть быстрее, если вы повторяете одну и ту же последовательность несколько раз.xrange()
должен восстанавливать целочисленный объект каждый раз, ноrange()
будет иметь реальные целочисленные объекты.источник
Хотя
xrange
это быстрее, чемrange
в большинстве случаев, разница в производительности довольно минимальна. Маленькая программа ниже сравнивает итерации по arange
и anxrange
:Результаты, приведенные ниже, показывают, что
xrange
это действительно быстрее, но недостаточно, чтобы потеть.Так что во что бы то ни стало используйте
xrange
, но если вы не на ограниченном оборудовании, не беспокойтесь об этом.источник
list_len
не используется, и поэтому вы запускаете этот код только для списков длиной 100.rtime = timeit.timeit('a=0;\nfor n in range(%d): a += n' % list_len, number=1000)