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 x나 for 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..10대 1...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

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

기본적으로, 우리 사이의 간격으로 범위 생각할 수 start와 end. 인 경우 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.