Почему диапазон (начало, конец) не включает конец?

>>> range(1,11)

дает тебе

[1,2,3,4,5,6,7,8,9,10]

Почему не 1-11?

Они просто решили сделать это наугад или это имеет какую-то ценность, которую я не вижу?


person Ryan    schedule 21.12.2010    source источник
comment
читать Дейкстра, ewd831   -  person SilentGhost    schedule 22.12.2010
comment
По сути, вы выбираете один набор ошибок по очереди за другим. Один набор с большей вероятностью приведет к преждевременному завершению ваших циклов, другой - к исключению (или переполнению буфера на других языках). Написав кучу кода, вы увидите, что выбор поведения range() имеет смысл гораздо чаще.   -  person John La Rooy    schedule 22.12.2010
comment
Ссылка на Dijkstra, ewd831: cs.utexas.edu/users/EWD/ ewd08xx / EWD831.PDF   -  person unutbu    schedule 22.12.2010
comment
@unutbu Эта статья Джикстры часто цитируется в этой теме, но не содержит здесь ничего ценного, люди используют ее просто как призыв к авторитету. Единственная соответствующая псевдопричина, которую он приводит для вопроса ОП, заключается в том, что он чувствует, что включение верхней границы становится неестественным и уродливым в частном случае, где последовательность пуста - это полностью субъективная позиция и легко возражал против, так что это мало что дает. Эксперимент с Mesa не представляет особой ценности без знания конкретных ограничений или методов оценки.   -  person sundar - Remember Monica    schedule 27.10.2013
comment
Аргумент @sundar Dijkstras состоит в том, что соглашение a < i <= b - единственное, для которого a и b никогда не должны покидать набор натуральных чисел, пока диапазон i либо пуст, либо находится внутри набора натуральных чисел. Хотя это в основном косметический аргумент, я думаю, что он вполне обоснован.   -  person andreasdr    schedule 21.04.2015
comment
@andreasdr Но даже если косметический аргумент верен, разве подход Python не создает новую проблему с удобочитаемостью? В общеупотребительном английском термин «диапазон» означает, что что-то находится в диапазоне от чего-то до чего-то - например, интервала. То, что len (list (range (1,2))) возвращает 1, а len (list (range (2))) возвращает 2, вам действительно нужно научиться переваривать.   -  person armin    schedule 24.07.2016
comment
Еще одно странное соглашение Python позаимствовано. : P Я предпочитаю моделировать естественную интуицию, а не делать что-то вроде января [0], февраля [1] и т. Д.   -  person Peter.k    schedule 21.11.2017
comment
Было бы неплохо, если бы range () предлагал возможность включения верхней границы. Меня устраивает, что range () по умолчанию является эксклюзивным, но бывают ситуации, когда включение делает синтаксис более читабельным.   -  person Shuklaswag    schedule 02.09.2018
comment
@Shuklaswag Я думаю, что диапазон (начало, конец + 1) будет намного более читаемым, чем диапазон (начало, конец, end_exclusive = False) или любой его вариант.   -  person kkawabat    schedule 11.11.2019
comment
@ sundar-ReinstateMonica Несложно возражать. Как?   -  person user76284    schedule 01.05.2020
comment
Если бы человек сказал, что ему нужен диапазон цветов от зеленого до красного, то очень немногие люди сказали бы, что не хотят красного. Таким образом, диапазон английских слов не подходит. Это не изменится, но я думаю, что это брешь в броне, потому что питон - разумный язык.   -  person Peter Moore    schedule 06.08.2020
comment
Функция Range в R возвращает минимальное и максимальное значение из входного вектора.   -  person SL5net    schedule 14.01.2021
comment
Реализация Ruby для диапазона: (1..5) = ›1, 2, 3, 4, 5 и (1 ... 5) =› 1, 2, 3, 4   -  person toquart    schedule 22.01.2021
comment
Я написал кучу кода, и такой выбор поведения range не имеет никакого смысла.   -  person EugZol    schedule 02.02.2021


Ответы (10)


Потому что чаще всего вызывается 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]
person moinudin    schedule 21.12.2010
comment
Если бы это было рассуждением, разве параметры не были бы range(start, count)? - person Mark Ransom; 22.12.2010
comment
ах, на самом деле это потому, что x может быть 0 - person Ryan; 22.12.2010
comment
@shogun По умолчанию начальное значение равно 0, т.е. range(10) эквивалентно range(0, 10). - person moinudin; 22.12.2010
comment
Ваш range1 не будет работать с диапазонами, размер шага которых отличается от 1. - person dimo414; 21.05.2015
comment
Вы объясняете, что диапазон (x) должен начинаться с 0, а x будет длиной диапазона. OK. Но вы не объяснили, почему диапазон (x, y) должен начинаться с x и заканчиваться на y-1. Если программисту нужен цикл for с i в диапазоне от 1 до 3, он должен явно добавить 1. Неужели дело в удобстве? - person armin; 24.07.2016
comment
Длина аргумента диапазона не применяется, если шаг не равен 1. т.е. range(0, 10, 2) это [0, 2, 4, 6, 8], который, очевидно, не имеет 10 элементов. Полагаю, в нем было бы end / step элемента, конечно, с округлением в меньшую сторону. - person dub stylee; 26.10.2016
comment
Несмотря на то, что это старый, такая простая вещь, как добавление +1 в диапазон, решила мою проблему. - person andyADD; 29.01.2017
comment
@ dimo414 Довольно просто иметь дополнительный параметр в качестве шага для работы функции диапазона. range1 = lambda start,end,step: range(start,end+1,step) for i in range(1,26): print(i) for i in range1(1,25,3): print(i) - person Doogle; 12.03.2017
comment
for i in range(len(li)): скорее антипаттерн. Следует использовать enumerate. - person hans; 06.03.2018
comment
предпочитаю - сильное слово - person Chris Calo; 24.12.2018
comment
Программисты предпочитают индексирование на основе 0, поэтому странно, что Python использует индексирование на основе 1 для стоп-позиций. Я не знаю многих языков программирования, но у всех было только одно соглашение. У Python их два. Примеры цикла for обманчивы. Когда я пишу 5:12 или диапазон (5, 12, 3), я имею в виду переход от 5 к 12. Если бы я хотел 11, я бы написал именно это. В Python вы используете число для обозначения числа перед ним ... но только иногда. - person bzip2; 18.01.2020
comment
вот где сияет Ruby: (1..10) vs (1 ... 10) - person toquart; 10.04.2020
comment
@ bzip2 Программисты не предпочитают, их учат тому, что в информатике из-за некоторых соглашений большинство вещей индексируется с помощью 0. Можно также создать эквивалентный набор одинаково действительных соглашений, в которых объекты индексируются, начиная с 3512 (или любого другого числа), а также существуют одинаково действительные арифметика и аксиоматическая математика. - person gented; 26.01.2021

Хотя здесь есть некоторые полезные алгоритмические объяснения, я думаю, что это может помочь добавить несколько простых аргументов из реальной жизни относительно того, почему это работает таким образом, что я нашел полезным при ознакомлении с этим предметом молодых новичков:

С чем-то вроде 'range (1,10)' может возникнуть путаница, если подумать, что пара параметров представляет собой «начало и конец».

Это собственно старт и «стоп».

Теперь, если бы оно было конечным значением, то да, можно было бы ожидать, что это число будет включено в качестве последней записи в последовательности. Но это еще не «конец».

Другие ошибочно называют этот параметр «count», потому что, если вы когда-либо используете только «range (n)», то он, конечно же, повторяет «n» раз. Эта логика нарушается, когда вы добавляете параметр запуска.

Поэтому важно помнить его название: «стоп». Это означает, что это точка, при достижении которой итерация немедленно останавливается. Не после этого момента.

Таким образом, хотя «start» действительно представляет собой первое значение, которое нужно включить, при достижении значения «stop» оно «прерывается», а не продолжает обрабатывать «это также» перед остановкой.

Одна аналогия, которую я использовал, объясняя это детям, заключается в том, что, по иронии судьбы, они лучше себя ведут, чем дети! Он не останавливается после того, как должен был - он останавливается немедленно, не завершая того, что он делал. (Они это понимают;))

Еще одна аналогия: когда вы ведете машину, вы не проезжаете знак "стоп / выход / уступите дорогу" и в итоге видите, что он сидит где-то рядом или сзади, Ваш автомобиль. Технически вы все еще не достигли этого, когда останавливаетесь. Это не входит в «вещи, которые вы передали в своем путешествии».

Я надеюсь, что кое-что из этого поможет в объяснении Pythonitos / Pythonitas!

person dingles    schedule 27.01.2016
comment
Это объяснение более интуитивно понятное. Спасибо - person Fred; 10.10.2019
comment
Вы пытаетесь накрасить свинью помадой. Различие между остановкой и концом абсурдно. Если я перейду от 1 к 7, я не сдал 7. Это просто недостаток Python - иметь разные соглашения для позиций начала и остановки. На других языках, включая человеческий, от X до Y означает от X до Y. В Python X: Y означает X: Y-1. Если у вас встреча с 9 до 11, говорите ли вы людям, что это с 9 до 12 или с 8 до 11? - person bzip2; 18.01.2020
comment
@ bzip2, питон не свинья, а змей. То, что вы называете несоответствиями и недостатками, не является: это выбор дизайна, сделанный разработчиками, который единообразно переносится по всему языку и позволяет миллионам программистов решать свои задачи. Если вам это не нравится, используйте расширение, которое предоставляет инклюзивные диапазоны, или переключитесь на другой язык. Ваши комментарии не способствуют пониманию Python, вместо этого они оскорбляют сообщество. Они также указывают на ваше непонимание природы эксклюзивных интервалов, потому что если у вас встреча с 9 до 11, в 11 вы будете свободны. - person Arthur Khazbs; 27.01.2021

Эксклюзивные линейки имеют некоторые преимущества:

Во-первых, каждый элемент в range(0,n) является допустимым индексом для списков длины n.

Также range(0,n) имеет длину n, а не n+1, как в инклюзивном диапазоне.

person sepp2k    schedule 21.12.2010

Он хорошо работает в сочетании с индексированием с нуля и 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().

person kindall    schedule 21.12.2010
comment
Согласитесь на нарезку. w = 'abc'; w[:] == w[0:len(w)]; w[:-1] == w[0:len(w)-1]; - person kevpie; 22.12.2010

Это также полезно для разделения диапазонов; range(a,b) можно разделить на range(a, x) и range(x, b), тогда как для включающего диапазона вы должны написать либо x-1, либо x+1. Хотя вам редко нужно разделять диапазоны, вы, как правило, довольно часто разбиваете списки, что является одной из причин, по которым разрезание списка l[a:b] включает a-й элемент, но не b-й. Тогда range наличие того же свойства делает его хорошо согласованным.

person xuanji    schedule 17.02.2013

Длина диапазона - это верхнее значение минус нижнее значение.

Это очень похоже на что-то вроде:

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
person Skilldrick    schedule 21.12.2010

Рассмотрим код

for i in range(10):
    print "You'll see this 10 times", i

Идея состоит в том, что вы получаете список длиной y-x, который вы можете (как вы видите выше) перебирать.

Ознакомьтесь с документами по Python для диапазона - они считают итерацию цикла основным вариант использования.

person Robert    schedule 21.12.2010

В основном в 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()
person Ashish Dixit    schedule 03.08.2018

Во многих случаях просто удобнее рассуждать.

В принципе, мы могли бы думать о диапазоне как о интервале между start и end. Если start <= end, длина интервала между ними равна end - start. Если бы len был фактически определен как длина, у вас было бы:

len(range(start, end)) == start - end

Однако мы считаем целые числа, входящие в диапазон, вместо того, чтобы измерять длину интервала. Чтобы указанное выше свойство оставалось истинным, мы должны включить одну из конечных точек и исключить другую.

Добавление параметра step похоже на введение единицы длины. В этом случае вы ожидаете

len(range(start, end, step)) == (start - end) / step

по длине. Чтобы получить счет, вы просто используете целочисленное деление.

person Arseny    schedule 29.05.2019
comment
Эти доводы в защиту непоследовательности Python забавны. Если мне нужен интервал между двумя числами, зачем мне использовать вычитание, чтобы получить разницу вместо интервала? Непоследовательно использовать разные соглашения об индексировании для начальной и конечной позиций. Зачем вам нужно писать 5:22, чтобы получить позиции с 5 по 21? - person bzip2; 18.01.2020
comment
Это не Python, он довольно распространен повсюду. В C, Java, Ruby вы называете это - person Arseny; 18.01.2020
comment
Я хотел сказать, что это обычное дело для индексации, а не то, что другие языки обязательно имеют такой же точный тип объекта - person Arseny; 09.04.2020

range(n) в Python возвращает значение от 0 до n-1. Соответственно, range(1,n) от 1 до n-1. Итак, если вы хотите опустить первое значение и получить также последнее значение (n), вы можете сделать это очень просто, используя следующий код.

for i in range(1, n + 1):
        print(i) #prints from 1 to n
person Nick Pantelidis    schedule 03.02.2021