2013-03-14 3 views
1

Я знаком с разницей между range() и xrange(). Я заметил что-то странное с xrange():странное поведение xrange() в Python 2

>>> xrange(1,10,2) 
xrange(1, 11, 2) 

>>> xrange(1,10,4) 
xrange(1, 13, 4) 

Функционально, это правильно:

>>> for item in xrange(1,10,4): 
...  print item 
... 
1 
5 
9 
>>> 

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

range() который теперь обеспечивает те же функциональные возможности в Python 3, как xrange в Python 2 ведет себя, как ожидалось:

>>> range(1,10,4) 
range(1, 10, 4) 
>>> range(1,10,2) 
range(1, 10, 2) 
>>> 
+2

Нет, 'xrange()' это не то же самое, как 'диапазона()' в Python 3. Последнее новое тип. Конечное значение * никогда * не включено ни в 'range()', ни 'xrange()'. Из-за вашего значения 'step' ни один, ни' 11', ни '10' в любом случае не включены в выходной диапазон. –

+0

@MartijnPieters Я согласен с вашей первой половиной комментария. Отредактировал мой вопрос. – 2013-03-14 12:53:14

+0

@MartijnPieters Теперь, когда значение стоп никогда не включалось, да, я это знаю. Почему объект xrange возвращается с остаточным значением в качестве последнего юридического значения + шаг? – 2013-03-14 12:54:21

ответ

2

xrange(1, 10, 4) равнозначно xrange(1, 13, 4). Чтобы использовать пример:

>>> for item in xrange(1,13,4): 
...  print item 
... 
1 
5 
9 
>>> 

xrange в Python 2 канонизирует start, stop, step аргументы. Внутренне реализация xrange сохраняет тройной старт, шаг и длину (количество элементов в объекте xrange) вместо начала, этапа и остановки. Вот как xrange.__repr__() реализован [1]:

rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)", 
          r->start, 
          r->start + r->len * r->step, 
          r->step); 

[1] https://github.com/replit/empythoned/blob/master/cpython/Objects/rangeobject.c

+0

Отлично. Спасибо, что поделились ссылкой на источник CPython. – 2013-03-14 13:23:31

+0

Я принимаю ваш ответ, так как это именно то, что было моим вопросом. – 2013-03-14 13:27:42

+0

Это ссылка на официальный источник CPython 3.3: http://hg.python.org/cpython/file/e45db319e590/Objects/rangeobject.c#l808 – 2013-03-14 13:36:56

3

Значение остановки в range или xrange всегда исключающими.

Цитата из docs (Python 2):

Если step положительный, последний элемент является крупнейшим start + i * stepменееstop; если step отрицательный, последний элемент наименьший start + i * stepбольшеstop.

И Python 3:

Для положительного step, содержимое диапазона г определяются по формуле, где r[i] = start + step*ii >= 0 и r[i] < stop.

Для отрицательного step, содержимое диапазона по-прежнему определяется по формуле r[i] = start + step*i, но ограничения i >= 0 и r[i] > stop.


О второй части вашего вопроса относительно repr() в xrange:

xrange(1, 10, 4) и xrange(1, 13, 4) идентичны и repr() для собственных объектов питона обычно возвращает действительный код питона, чтобы воссоздать объект. Это не обязательно должен быть точно такой же код python, который первоначально создавал объект.

+1

Да, я буду принимать ваш ответ, так как вторая половина ответа - это то, что я искал. Благодарю. – 2013-03-14 12:57:50

+0

Извините, я принял ответ @ zodiac, так как он даже указал мне на исходный код, который дает мне точный ответ, который я искал. – 2013-03-14 13:28:27

2

Действительно ли это имеет значение?

эффект такой же. Ни 10, ни 11 не включены в выход xrange(), а xrange(1, 11, 2) - эквивалент - xrange(1, 10, 2).

Тип диапазона Python 2 (результат xrange()) сохраняет длину диапазона, а не конечное значение, поэтому для создания вывода repr он вычисляет это конечное значение для вас. И поскольку вы использовали значение шага, вычисление показывает результат формулы start + length * step. Для реализации длина является более важным значением, значение end можно безопасно отбрасывать и пересчитывать по мере необходимости.

Таким образом, при создании xrange(1, 10, 2), он вычисляет длину диапазона и сохраняет что вместо конечного значения:

if (step > 0 && lo < hi) 
return 1UL + (hi - 1UL - lo)/step; 
else if (step < 0 && lo > hi) 
return 1UL + (lo - 1UL - hi)/(0UL - step); 
else 
return 0UL; 

питон 3 Range объекта сохраняет конечное значение в дополнение к длине , поэтому вы можете запросить объект для него и отобразить его на выходе repr.

+0

Я не уверен, почему вы спрашиваете: «Это действительно имеет значение?». Я знаю, что эффект тот же. Я этого не спрашивал. Так или иначе. – 2013-03-14 12:58:51

Смежные вопросы