Python / range() / 연속된 수 또는 일정 간격의 연속된 수를 만드는 함수

Python의 range()는 일정 간격의 정수 수열을 나타내는 불변 시퀀스를 만듭니다. 시작값은 포함하고 끝 경계인 stop은 포함하지 않으며, step의 부호로 증가·감소 방향을 정합니다. 모든 값을 미리 담는 리스트나 한 번씩 소비하는 제너레이터와는 다릅니다.

range(stop), range(start, stop, step)의 기본 규칙

range 공식 설명의 세 가지 형식은 range(stop), range(start, stop), range(start, stop, step)입니다. 생략한 start는 0, step은 1입니다. 인수는 정수 또는 정수 인덱스 규약을 지원하는 객체여야 하며, 일반 실수나 숫자 문자열을 자동으로 바꾸지 않습니다.

예제는 Python 3에서 전체 코드를 UTF-8의 range_example.py로 저장한 뒤 python range_example.py로 실행합니다. 환경에 따라 python3을 사용하며 각 예제는 파일 내용을 교체해 독립적으로 실행할 수 있습니다. 작은 범위는 list()로 값 전체를 확인합니다.

print(list(range(4)))
print(list(range(1, 6)))
print(list(range(1, 10, 2)))

예상 결과:

[0, 1, 2, 3]
[1, 2, 3, 4, 5]
[1, 3, 5, 7, 9]

range(4)는 0~3이고 range(1, 6)은 1~5입니다. 1부터 5까지 포함하려는 증가 범위라면 stop을 6으로 정합니다. step이 2이면 마지막 값이 반드시 stop 바로 앞 숫자가 되는 것은 아니며, 간격과 경계 조건을 모두 만족하는 값까지만 생성합니다.

음수 step과 빈 범위

양수 step에서는 값이 stop보다 작은 동안, 음수 step에서는 값이 stop보다 큰 동안 포함됩니다. 감소하려면 음수 간격을 지정해야 하며 방향이 맞지 않으면 오류 대신 빈 범위가 됩니다.

print(list(range(10, -5, -3)))
print(list(range(5, 0, -1)))
print(list(range(5, 0)))
print(list(range(0, 5, -1)))
print(list(range(3, 3)))
[10, 7, 4, 1, -2]
[5, 4, 3, 2, 1]
[]
[]
[]

range(10, -5, -3)은 10, 7, 4, 1, -2입니다. 다음 값 -5는 stop 자체라서 제외됩니다. 5부터 1까지 내려가려면 range(5, 0, -1)처럼 끝 경계를 0으로 잡습니다. 시작과 끝이 같아도 빈 범위이며, 빈 범위로 반복하면 본문을 한 번도 실행하지 않습니다.

리스트가 아니지만 인덱싱과 반복이 가능합니다

print(range(...))는 모든 원소 대신 범위의 표현을 보여 줍니다. range는 시작·끝·간격을 바탕으로 값을 계산하는 시퀀스이므로 길이 확인, 인덱스, 슬라이스와 포함 여부 검사를 지원합니다. 불변이므로 특정 위치의 값을 대입해서 바꿀 수는 없습니다.

numbers = range(2, 10, 2)
print(numbers)
print(len(numbers))
print(numbers[0], numbers[-1])
print(list(numbers[1:3]))
print(6 in numbers, 7 in numbers)
print(list(numbers))
print(list(numbers))
range(2, 10, 2)
4
2 8
[4, 6]
True False
[2, 4, 6, 8]
[2, 4, 6, 8]

같은 range를 두 번 리스트로 바꿔도 같은 원소가 나옵니다. range 객체 자체는 반복할 때 소진되는 제너레이터가 아니기 때문입니다. iter(numbers)로 따로 만든 반복자는 소비되므로 range 객체와 그 반복자를 혼동하지 않습니다. 슬라이스 결과도 range이며, 예제에서는 내용 확인을 위해 리스트로 바꿨습니다.

step 0, 실수와 문자열의 오류

간격 0은 진행 방향을 정의하지 못하므로 ValueError입니다. 3.0은 값이 정수처럼 보여도 float이고 "3"은 문자열이므로 각각 TypeError가 발생합니다.

for arguments in ((1, 5, 0), (3.0,), ("3",)):
    try:
        print(range(*arguments))
    except (ValueError, TypeError) as error:
        print(type(error).__name__)
ValueError
TypeError
TypeError

정수 문자열 입력이 필요하면 별도 검증 후 int()로 바꿀 수 있습니다. 그러나 실수를 무조건 int로 절삭하면 의도와 다른 범위를 만들 수 있으므로 입력 정책을 먼저 정합니다. 예제의 예외 처리는 세 입력을 비교하기 위한 것이며, 오류를 무시하고 작업이 성공한 것으로 처리하는 패턴은 아닙니다.

반복 횟수와 항목 번호에 맞게 사용

range 반복문은 정해진 횟수나 정수 단계가 필요할 때 적합합니다. 항목 자체만 필요하면 리스트를 직접 반복하고, 항목과 번호가 함께 필요하면 enumerate()를 쓰면 인덱스 계산을 줄일 수 있습니다.

for number in range(1, 4):
    print("Step", number)

names = ["Ada", "Bo"]
for number, name in enumerate(names, start=1):
    print(number, name)
Step 1
Step 2
Step 3
1 Ada
2 Bo

첫 번째 반복은 1~3의 세 단계입니다. 두 번째 반복의 start=1은 항목에 붙이는 번호의 시작을 바꿀 뿐 리스트의 첫 항목을 건너뛰지 않습니다. 실제 인덱스가 필요하거나 인덱스로 위치를 계산하는 문제에서는 range(len(items))도 사용할 수 있습니다.

아주 큰 범위에서는 자원과 길이 한계를 구분합니다

range는 전체 정수 리스트를 저장하지 않으므로 큰 경계를 표현할 수 있지만, 모든 원소를 실제로 반복하는 시간까지 줄여 주지는 않습니다. CPython에서는 len()의 길이 표현 한계 때문에 범위를 만들 수 있어도 길이 계산에서 OverflowError가 날 수 있습니다.

import sys

numbers = range(sys.maxsize + 1)
print(numbers[0])
print(numbers[-1] == sys.maxsize)
try:
    print(len(numbers))
except OverflowError:
    print("OverflowError")
0
True
OverflowError

이 예제는 처음·마지막 원소와 길이 오류만 확인하며 전체를 순회하지 않습니다. sys.maxsize의 값은 환경에 따라 다릅니다. 큰 범위를 무심코 list()로 바꾸지 말고, 실제 필요한 구간만 반복하거나 결과를 단계별로 처리합니다.