>>> range(1,11)
дает тебе
[1,2,3,4,5,6,7,8,9,10]
Почему не 1-11?
Они просто решили сделать это случайным образом или это имеет какое-то значение, которого я не вижу?
range()
имеет смысл гораздо чаще
>>> range(1,11)
дает тебе
[1,2,3,4,5,6,7,8,9,10]
Почему не 1-11?
Они просто решили сделать это случайным образом или это имеет какое-то значение, которого я не вижу?
range()
имеет смысл гораздо чаще
Ответы:
Потому что более распространенным является вызов с range(0, 10)
возвратом, [0,1,2,3,4,5,6,7,8,9]
который содержит 10 равных элементов len(range(0, 10))
. Помните, что программисты предпочитают индексирование на основе 0.
Также рассмотрим следующий общий фрагмент кода:
for i in range(len(li)):
pass
Можете ли вы увидеть, что если бы range()
дошло до того, len(li)
что это было бы проблематично? Программист должен был бы явно вычесть 1. Это также следует общей тенденции программистов, предпочитающих for(int i = 0; i < 10; i++)
более for(int i = 0; i <= 9; i++)
.
Если вы часто вызываете диапазон с начала 1, вы можете определить свою собственную функцию:
>>> def range1(start, end):
... return range(start, end+1)
...
>>> range1(1, 10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
range(start, count)
?
range(10)
есть эквивалентно range(0, 10)
.
range1
не будете работать с диапазонами, размер шага которых отличается от размера 1
.
for i in range(len(li)):
скорее антипаттерн. Надо использовать enumerate
.
Хотя здесь есть несколько полезных алгоритмических объяснений, я думаю, что это может помочь добавить несколько простых «реальных» рассуждений о том, почему это работает таким образом, что я нашел полезным при представлении предмета молодым новичкам:
С чем-то вроде «range (1,10)» может возникнуть путаница, если подумать, что пара параметров представляет «начало и конец».
Это фактически начало и «остановка».
Теперь, если бы это было «конечное» значение, то да, вы могли бы ожидать, что это число будет включено в качестве последней записи в последовательности. Но это не «конец».
Другие ошибочно называют этот параметр «count», потому что если вы когда-либо используете «range (n)», то он, конечно, повторяет «n» раз. Эта логика ломается, когда вы добавляете параметр запуска.
Таким образом, ключевой момент заключается в том, чтобы запомнить его название: « стоп ». Это означает, что это точка, в которой при достижении итерация будет немедленно остановлена. Не после этого момента.
Таким образом, хотя «start» действительно представляет первое значение, которое должно быть включено, при достижении значения «stop» оно «ломается», а не продолжает обрабатывать «то же самое» перед остановкой.
Одна аналогия, которую я использовал, объясняя это детям, заключается в том, что, по иронии судьбы, он ведет себя лучше, чем дети! Он не останавливается после того, как должен был - он останавливается немедленно, не заканчивая то, что делал. (Они получают это;))
Другая аналогия - когда вы ведете машину, вы не проходите мимо знака «стоп / выход / уступить дорогу» и в конечном итоге сидите рядом с вашей машиной или позади нее. Технически вы все еще не достигли этого, когда остановитесь. Это не входит в «вещи, которые вы прошли в своем путешествии».
Я надеюсь, что это поможет объяснить Pythonitos / Pythonitas!
Хорошо работает в сочетании с индексацией на основе нуля и len()
. Например, если у вас есть 10 элементов в списке x
, они нумеруются от 0 до 9. range(len(x))
дает вам 0-9.
Конечно, люди скажут вам, что делать больше на Pythonic for item in x
или for index, item in enumerate(x)
скорее чем for i in range(len(x))
.
Срез также работает таким же образом: foo[1:4]
это пункты 1-3 из foo
(имея в виду, что пункт 1 на самом деле является вторым элементом из-за индексации на основе нуля). Для согласованности они оба должны работать одинаково.
Я думаю об этом как: «первый номер, который вы хотите, а затем первый номер, который вы вы не хотите». Если вы хотите 1-10, первое число, которое вы не хотите, это 11, так что это range(1, 11)
.
Если в конкретном приложении это становится громоздким, достаточно легко написать небольшую вспомогательную функцию, которая добавляет 1 к конечному индексу и вызовам range()
.
w = 'abc'; w[:] == w[0:len(w)]; w[:-1] == w[0:len(w)-1];
def full_range(start,stop): return range(start,stop+1) ## helper function
for index, item in enumerate(x)
чтобы избежать путаницы
Это также полезно для разделения диапазонов; range(a,b)
можно разделить на range(a, x)
и range(x, b)
, тогда как с включенным диапазоном вы бы написали либо x-1
или x+1
. Хотя вам редко требуется разделять диапазоны, вы, как правило, довольно часто разделяете списки, что является одной из причин, по которой разделение списка l[a:b]
включает в себя a-й элемент, но не b-й. Тогда range
наличие того же свойства делает его хорошо согласованным.
Длина диапазона - это верхнее значение минус нижнее значение.
Это очень похоже на что-то вроде:
for (var i = 1; i < 11; i++) {
//i goes from 1 to 10 in here
}
на языке C-стиля.
Также как и ассортимент Руби:
1...11 #this is a range from 1 to 10
Тем не менее, Ruby признает, что много раз вы захотите включить значение терминала, и предлагает альтернативный синтаксис:
1..10 #this is also a range from 1 to 10
1..10
против 1...10
того трудно различить при чтении коды!
В основном в python range(n)
итерирует n
время, которое имеет исключительную природу, поэтому оно не дает последнего значения при печати, мы можем создать функцию, которая дает инклюзивное значение, это означает, что она также будет печатать последнее значение, упомянутое в диапазоне.
def main():
for i in inclusive_range(25):
print(i, sep=" ")
def inclusive_range(*args):
numargs = len(args)
if numargs == 0:
raise TypeError("you need to write at least a value")
elif numargs == 1:
stop = args[0]
start = 0
step = 1
elif numargs == 2:
(start, stop) = args
step = 1
elif numargs == 3:
(start, stop, step) = args
else:
raise TypeError("Inclusive range was expected at most 3 arguments,got {}".format(numargs))
i = start
while i <= stop:
yield i
i += step
if __name__ == "__main__":
main()
Рассмотрим код
for i in range(10):
print "You'll see this 10 times", i
Идея в том, что вы получите список длины y-x
, который вы можете (как вы видели выше) повторить.
Читайте в документации по Python для диапазона - они рассматривают цикл итерации в качестве основного варианта использования.
Это просто удобнее рассуждать во многих случаях.
По сути, мы можем думать о диапазоне как об интервале между start
и end
. Если start <= end
длина интервала между ними равна end - start
. Если бы на len
самом деле была определена длина, вы бы имели:
len(range(start, end)) == start - end
Однако мы подсчитываем целые числа, включенные в диапазон, а не измеряем длину интервала. Чтобы оставить указанное выше свойство истинным, мы должны включить одну из конечных точек и исключить другую.
Добавление step
параметра похоже на введение единицы длины. В этом случае вы ожидаете
len(range(start, end, step)) == (start - end) / step
для длины. Чтобы получить количество, вы просто используете целочисленное деление.