range (start, end)에 end가 포함되지 않는 이유는 무엇입니까?


305
>>> range(1,11)

당신을 제공합니다

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

왜 1-11이 아닙니까?

그들은 무작위로 그렇게하기로 결정 했습니까? 아니면 내가 볼 수없는 가치가 있습니까?


11
Dijkstra를 읽고, ewd831
SilentGhost

11
기본적으로 하나의 버그를 다른 버그로 선택합니다. 한 세트는 루프가 조기에 종료 될 가능성이 높고 다른 세트는 예외 (또는 다른 언어의 버퍼 오버 플로우)를 유발할 수 있습니다. 많은 코드를 작성하면 동작 선택이 range()훨씬 더 의미가 있음을 알 수 있습니다.
John La Rooy

32
Dijkstra, ewd831에 연결 : cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF
unutbu

35
@unutbu이 지크 스트라 기사는이 주제에서 자주 인용되지만 여기서는 아무 가치가 없다. 그가 OP의 질문에 대해 유일하게 관련하는 의사 이유는 상한을 포함하는 것이 순서가 비어 있는 특별한 경우 에 "부자연스럽고"추악해진다는 느낌이 들기 때문이다 . 그래서 테이블에 많은 것을 가져 오지 않습니다. Mesa를 사용한 "실험"은 특정 제약이나 평가 방법을 알지 못하면 큰 가치가 없습니다.
sundar-복원 모니카

6
@andreasdr 그러나 외관상의 논증이 유효하더라도 파이썬의 접근법이 새로운 가독성 문제를 일으키지 않습니까? 일반적으로 사용되는 영어에서 "범위"라는 용어 무언가 무언가와 같은 것, 예를 들어 간격과 같은 것을 의미합니다. len (list (range (1,2))) 1을 반환하고 len (list (range (2))) 2를 반환하면 실제로 소화하는 법을 배워야합니다.
armin

답변:


245

10 개의 요소를 포함하는를 range(0, 10)반환 [0,1,2,3,4,5,6,7,8,9]하는 것이 더 일반적이기 때문에 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]

48
그것이 추론이라면 매개 변수는 그렇지 range(start, count)않습니까?
Mark Ransom

3
@shogun 시작 값의 기본값은 0입니다. 즉와 range(10)같습니다 range(0, 10).
moinudin

4
귀하가 range1아닌 다른 스텝 크기가 범위 작동하지 않습니다 1.
dimo414

6
range (x)는 0으로 시작해야하고 x는 "범위의 길이"라고 설명합니다. 확인. 그러나 range (x, y)가 x로 시작하고 y-1로 끝나는 이유를 설명하지 않았습니다. 프로그래머가 i 범위가 1에서 3 사이 인 for-loop를 원한다면 명시 적으로 1을 추가해야합니다. 이것이 실제로 편의성입니까?
armin

7
for i in range(len(li)):오히려 반 패턴입니다. 하나를 사용해야합니다 enumerate.
hans

27

여기에는 유용한 알고리즘 설명이 있지만이 방법이 왜 작동하는지에 대한 간단한 '실제 생활'추론을 추가하는 데 도움이 될 수 있다고 생각합니다.

'range (1,10)'과 같은 매개 변수 쌍이 "시작 및 끝"을 나타내는 것으로 생각하면 혼동 될 수 있습니다.

실제로 시작과 "중지"입니다.

이 경우 지금 있었다 다음 "끝"값을, 그래, 당신은 그 숫자가 순서의 마지막 항목으로 포함된다 기대할 수 있습니다. 그러나 "끝"이 아닙니다.

'range (n)'만 사용한다면 물론 'n'번 반복하기 때문에 다른 사람들은 실수로이 매개 변수를 "count"라고 부릅니다. 이 논리는 시작 매개 변수를 추가 할 때 분류됩니다.

요점은 " stop " 이라는 이름을 기억하는 것 입니다. 즉, 도달하면 반복이 즉시 중지되는 지점입니다. 그 시점 이후 가 아닙니다 .

따라서 "시작"은 실제로 포함되는 첫 번째 값을 나타내지 만 "중지"값에 도달하면 중지하기 전에 '해당 값'을 계속 처리하지 않고 '파손'합니다.

아이들에게 이것을 설명 할 때 사용한 비유 중 하나는 아이러니하게도 아이들보다 더 잘 행동한다는 것입니다! 예정된 후에 멈추지 않습니다 -하고 있던 일을 끝내지 않고 즉시 멈 춥니 다. (그들은 이것을 얻는다;))

또 다른 비유-자동차를 운전할 때 정지 / 수율 / '주십시오'표시를 전달 하지 않고 자동차 옆 또는 뒤에 앉아있는 상태로 끝납니다. 기술적으로 당신은 당신이 멈출 때 여전히 그것에 도달하지 않았습니다. '여행에 통과 한 것들'에는 포함되어 있지 않습니다.

그 중 일부가 Pythonitos / Pythonitas에 설명하는 데 도움이되기를 바랍니다.


이 설명은 더 직관적입니다. 감사합니다
Fred

아이들의 설명은 재미 있습니다!
Antony Hatchkins

1
돼지에게 립스틱을 바르려고합니다. "중지"와 "종료"의 구별은 터무니 없습니다. 1에서 7로 가면 7을 통과하지 못했습니다. 시작 및 중지 위치에 대해 다른 규칙을 갖는 것은 단순히 Python의 결함입니다. 인간 언어를 포함한 다른 언어에서 "X에서 Y로"는 "X에서 Y로"를 의미합니다. 파이썬에서 "X : Y"는 "X : Y-1"을 의미합니다. 9시에서 11시 사이에 미팅이있는 경우, 9시에서 12시, 또는 8시에서 11시 사이의 사람들에게 이야기합니까?
bzip2

24

독점 범위에는 몇 가지 이점이 있습니다.

한 가지 점은 각 항목 range(0,n)의 길이 목록에 대한 유효한 색인입니다 n.

또한 포함 범위가 아닌 range(0,n)의 길이 를가집니다.nn+1


18

0부터 시작하는 인덱싱 및와 함께 잘 작동합니다 len(). 예를 들어, 목록에 10 개의 항목이 있으면 x0-9로 번호가 매겨집니다. range(len(x))0-9를 제공합니다.

물론, 사람들은 더 파이썬이 할의 당신을 말할 것이다 for item in xfor index, item in enumerate(x)보다는 for i in range(len(x)).

슬라이싱도 작동합니다 : foo[1:4]1-3의 항목입니다 foo(항목 1은 실제로 0부터 시작하는 인덱싱으로 인해 두 번째 항목입니다). 일관성을 유지하려면 둘 다 동일한 방식으로 작동해야합니다.

"원하는 첫 번째 숫자 다음에 원하지 않는 첫 번째 숫자 "라고 생각합니다. 1-10을 원하면 원하지 않는 첫 번째 숫자는 11 range(1, 11)입니다.

특정 응용 프로그램에서 번거로워지면 끝 색인에 1을 추가하고을 호출하는 작은 도우미 함수를 작성하는 것이 쉽습니다 range().


1
슬라이스에 동의합니다. w = 'abc'; w[:] == w[0:len(w)]; w[:-1] == w[0:len(w)-1];
kevpie

def full_range(start,stop): return range(start,stop+1) ## helper function
nobar

아마도 열거 예제는 for index, item in enumerate(x)혼란을 피하기 위해 읽어야 할 것입니다
seans

@seans 감사합니다.
kindall

12

범위 분할에도 유용합니다. range(a,b)로 분할 될 수 있습니다 range(a, x)range(x, b)포괄적 인 범위 당신이 중 하나를 작성합니다 반면, x-1또는 x+1. 범위를 분할 할 필요는 거의 없지만 목록을 자주 분할하는 경향이 있습니다. 이는 목록을 슬라이스 l[a:b]하면 a 번째 요소는 포함되지만 b 번째 요소는 포함하지 않는 이유 중 하나입니다 . 그런 다음 range동일한 속성을 가지면 일관성이 좋습니다.


11

범위의 길이는 최고 값에서 최저값을 뺀 값입니다.

다음과 매우 유사합니다.

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

17
가! 나는 루비를 사용하지 않는,하지만 난 그것을 상상할 수있는 1..101...10코드를 읽을 때 구별하기 어려운 것!
moinudin

6
@marcog-당신이 두 가지 형태가 존재한다는 것을 알고있을 때 당신의 눈은 그 차이에
맞습니다

11
루비의 범위 연산자는 완벽하게 직관적입니다. 양식이 길수록 시퀀스가 ​​짧아집니다. 기침
Russell Borogove

4
@Russell, 아마도 1 ............ 20은 1..10과 같은 범위를 제공해야합니다. 이제는 전환 가치가있는 구문 설탕이 될 것입니다. ;)
kevpie

4
@Russell 여분의 점이 범위를 벗어난 마지막 아이템을 압박합니다 :)
Skilldrick

5

파이썬에서 기본적으로 시간을 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()

4

코드를 고려하십시오

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

아이디어는 길이 목록을 얻는 것입니다. y-x (위에서 볼 수 있듯이) 반복 할 수 있다는 것입니다.

범위 에 대한 파이썬 문서 를 읽으십시오 -그들은 루프의 반복을 주요 유스 케이스로 간주합니다.


1

많은 경우에 대해 추론하는 것이 더 편리합니다.

기본적으로, 우리 사이의 간격으로 범위 생각할 수 startend. 인 경우 start <= end간격이 길이입니다 end - start. len실제로 길이로 정의 된 경우 다음 이 있습니다.

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

그러나 구간의 길이를 측정하는 대신 범위에 포함 된 정수를 계산합니다. 위의 속성을 유지하려면 끝점 중 하나를 포함하고 다른 끝점을 제외해야합니다.

step매개 변수를 추가하는 것은 길이 단위를 도입하는 것과 같습니다. 이 경우에, 당신은 기대할 것입니다

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

길이. 카운트를 얻으려면 정수 나누기를 사용하십시오.


파이썬의 불일치에 대한 이러한 방어는 유쾌합니다. 두 숫자 사이의 간격을 원한다면 왜 뺄셈을 사용하여 간격 대신 차이를 얻습니까? 시작 및 종료 위치에 서로 다른 색인 규칙을 사용하는 것은 일치하지 않습니다. 위치 5에서 21을 얻기 위해 왜 "5:22"를 작성해야합니까?
bzip2

그것은 파이썬이 아니며, 전반적으로 꽤 일반적입니다. C, Java, Ruby에서는 이름을
지어 라

다른 언어들도 반드시 같은 종류의 객체를 가지고있는 것이 아니라 인덱싱이 일반적이라고 말하려고했습니다
Arseny
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.