
이미지 출처: Wikimedia Commons, leonie wise (Unsplash) · CC0
장을 보러 가기 전에 살 것을 적어 둡니다. 사과, 우유, 계란, 빵, 커피. 종이 한 장에 다섯 줄이면 끝입니다. 그런데 3편에서 배운 변수로 담으려면 이름을 다섯 개 지어야 합니다. item1, item2, 하고 세다가 물건이 하나 늘면 이름도 하나 더 지어야 합니다.
파이썬에는 이 메모지를 그대로 옮기는 문법이 있습니다. 대괄호 하나면 됩니다.
cart = ["사과", "우유", "계란", "빵", "커피"]
print(cart)
print(len(cart), "개")📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
['사과', '우유', '계란', '빵', '커피']
5 개
이름은 cart 하나뿐인데 다섯 개가 다 들어갔고, len으로 세어 보니 5개입니다. 이것이 리스트입니다. 오늘은 이 장바구니 하나로 리스트가 하는 일을 거의 다 해 봅니다. 먼저 리스트가 무엇인지 잡고, 그다음 열아홉 줄짜리 코드를 여섯 토막으로 나눠 위에서 아래로 읽습니다.
리스트가 뭔가요 — 칸이 이어진 서랍장
변수 하나에는 값 하나가 들어갑니다. 리스트는 칸이 이어진 서랍장에 이름표 하나를 붙인 것입니다. 칸마다 번호가 있고, 그 번호가 1이 아니라 0에서 시작합니다. 왜 0인지는 잠시 뒤 그림으로 봅니다.
파이썬 공식 문서는 이 서랍장을 **변경 가능한 순서열(mutable sequence)**이라고 부릅니다. 말이 딱딱하니 둘로 나눠 봅니다. 순서열은 값 여러 개를 순서대로 한 줄로 세운 것. 변경 가능은 만든 뒤에도 넣고, 빼고, 갈아 끼울 수 있다는 뜻입니다. 문자열도 글자를 순서대로 세운 순서열이지만, 만들고 나서 글자 하나를 바꾸지는 못합니다. 리스트는 됩니다. 이 차이를 뒤에서 여러 번 만납니다.

변수 다섯 개로 담으면 이름도 다섯입니다. 리스트는 이름 하나에 칸 다섯이고, 칸마다 0부터 번호가 붙습니다.
성질은 넷입니다. 전부 아래 열아홉 줄 안에 있습니다.
| 성질 | 뜻 | 위 코드에서 |
|---|---|---|
| 순서가 있다 | 넣은 순서가 그대로 남는다. 첫 칸과 둘째 칸이 구분된다 | cart[0]은 사과, cart[1]은 우유 |
| 바꿀 수 있다 | 만든 뒤에 넣고, 빼고, 칸 하나를 갈아 끼울 수 있다 | append, remove, cart[0] = "청사과" |
| 같은 값이 여러 번 들어간다 | 한 값이 두 칸 이상 차지해도 된다 | ["사과", "사과"]는 길이 2인 정상 리스트 |
| 종류를 가리지 않는다 | 문자열·숫자·참거짓, 다른 리스트까지 담긴다 | ["사과", 3, 1.5, True] |
앞으로 이 뜻으로 쓰는 낱말입니다.
| 용어 | 뜻 |
|---|---|
| 원소(element) | 리스트 안에 든 값 하나. 서랍장의 칸 하나 |
| 길이 | 원소의 개수. len(cart) |
| 인덱스(index) | 원소의 자리 번호. 앞에서 0부터, 뒤에서 -1부터 |
| 슬라이싱(slicing) | 인덱스 두 개로 구간을 잘라 새 리스트를 만드는 문법 |
| 메서드(method) | 리스트에 점을 찍어 시키는 일. cart.append("치약") |
리스트가 필요한 순간은 개수가 미리 정해지지 않을 때입니다. 시험 점수, 사용자가 입력한 줄들, 장바구니. 셋 다 몇 개가 들어올지 코드를 쓰는 시점에는 모릅니다. 다음 편의 for 반복문이 리스트를 한 칸씩 도는 문법이라, 여기서 리스트를 잡아 두면 반복문이 훨씬 쉽게 읽힙니다.
오늘 읽을 열아홉 줄
아래 코드가 오늘의 전부입니다. 주석은 일부러 뺐고, 소제목마다 "몇 줄"인지 적어 두었으니 그 토막만 찾아 읽으면 됩니다. 지금은 절반만 읽혀도 정상입니다. 끝에 가면 같은 코드에 주석이 붙어 있습니다.
cart = ["사과", "우유", "계란", "빵", "커피"]
print(cart)
print(len(cart))
print(cart[0], cart[2])
print(cart[-1])
print(cart[1:4])
print(cart[:2], cart[3:])
cart.append("치약")
cart.insert(1, "바나나")
print(cart)
cart.remove("우유")
last = cart.pop()
print(last, cart)
print("계란" in cart)
print(cart.index("빵"))
cart[0] = "청사과"
print(cart)
cart.sort()
print(cart)
출력 열두 줄은 옆에 두고 토막마다 대조합니다.
['사과', '우유', '계란', '빵', '커피']
5
사과 계란
커피
['우유', '계란', '빵']
['사과', '우유'] ['빵', '커피']
['사과', '바나나', '우유', '계란', '빵', '커피', '치약']
치약 ['사과', '바나나', '계란', '빵', '커피']
True
3
['청사과', '바나나', '계란', '빵', '커피']
['계란', '바나나', '빵', '청사과', '커피']
1~3줄 · 대괄호 열고, 쉼표로 세우고, 대괄호 닫기
문법은 이게 전부입니다. [와 ] 사이에 값을 쉼표로 늘어놓으면 리스트입니다.
cart = ["사과", "우유", "계란", "빵", "커피"]
print(cart)
print(len(cart), type(cart))
empty = []
mixed = ["사과", 3, 1.5, True]
print(empty, len(empty))
print(mixed)📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
['사과', '우유', '계란', '빵', '커피']
5 <class 'list'>
[] 0
['사과', 3, 1.5, True]
print(cart)가 찍은 첫 줄에 대괄호가 그대로 보입니다. 파이썬은 리스트를 사람이 쓴 모양 그대로 되돌려 줍니다. 문자열이 큰따옴표가 아니라 작은따옴표로 나오는 건 파이썬의 표시 습관이고, 코드에서 두 따옴표는 같은 뜻입니다.
len(cart)는 칸 수. 여기서는 5입니다. type(cart)가 알려 주는 <class 'list'>가 이 자료형의 정식 이름입니다. 값이 하나도 없는 []도 멀쩡한 리스트. 길이는 0입니다. 문자열과 숫자와 참·거짓을 한 리스트에 섞어도 파이썬은 막지 않습니다. 다만 섞어 두면 나중에 계산할 때 3편의 TypeError를 다시 만나기 쉬워서, 같은 종류만 담는 편이 관리하기 편합니다.
4~5줄 · 첫 칸은 한 칸도 떨어지지 않았으니 0
값 하나를 꺼낼 때는 이름 뒤에 대괄호를 붙이고 자리 번호를 씁니다. 그 번호가 인덱스입니다.
왜 1이 아니라 0에서 시작할까. 이 번호가 "몇 번째"가 아니라 **"맨 앞에서 몇 칸 떨어졌나"**라서 그렇습니다. 첫 칸은 한 칸도 떨어지지 않았으니 0. 파이썬 공식 자습서는 여기서 한발 더 나가, 번호를 칸이 아니라 칸과 칸 사이의 눈금으로 보라고 권합니다. 맨 앞 눈금이 0이고, 첫 칸을 지나면 눈금 1입니다. 저는 이 설명을 좋아합니다. 0에서 시작하는 것과 잠시 뒤 슬라이싱에서 끝 번호가 빠지는 것을 그림 하나로 끝낼 수 있어서입니다.
![다섯 칸 위에 0부터 5까지 눈금이 있는 자, 아래에 -5부터 -1까지 눈금이 있는 자가 놓여 있고, cart[2]가 눈금 2 뒤의 계란 칸을 가리키며 cart[1:4]가 눈금 1에서 4까지 세 칸을 감싸고 cart[5]는 눈금 5 뒤에 칸이 없다고 표시한 그림](/uploads/python-list-ruler.png)
번호는 칸 사이의 눈금입니다. cart[2]는 눈금 2 바로 뒤의 칸, cart[1:4]는 눈금 1에서 눈금 4까지의 세 칸입니다. 눈금 5 뒤에는 칸이 없습니다.
그래서 마지막 칸의 번호는 언제나 len(cart) - 1입니다. 칸이 다섯이면 마지막은 4번.
cart = ["사과", "우유", "계란", "빵", "커피"]
print(cart[0], cart[2], cart[4])
print(cart[-1], cart[-5])
print(len(cart))
print(cart[5]) # 이 줄에서 멈춥니다 — 지우고 다시 실행해 보세요📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
앞의 세 줄은 이렇게 나옵니다.
사과 계란 커피
커피 사과
5
마지막 줄에서 멈춥니다.
IndexError: list index out of range
리스트 인덱스가 범위를 벗어났다는 뜻입니다. 칸이 다섯인데 5번을 달라고 했으니 줄 것이 없습니다. 원인은 거의 항상 하나입니다. 칸 수와 마지막 번호를 같다고 착각한 것. 위 그림에서 눈금 5 뒤에 칸이 없는 자리가 바로 이 에러입니다.
음수 인덱스는 뒤에서부터 세는 번호입니다. cart[-1]이 맨 뒤, cart[-2]가 그 앞. 길이를 몰라도 마지막 값을 꺼낼 수 있으니 len(cart) - 1을 매번 계산할 일이 없습니다.
6~7줄 · 콜론으로 자르면 끝 번호가 빠지는 이유
여러 칸을 한 번에 꺼내는 문법이 슬라이싱입니다. 대괄호 안에 콜론을 넣고 [시작:끝]. 결과는 원본에서 잘라 낸 새 리스트입니다.
cart = ["사과", "우유", "계란", "빵", "커피"]
print(cart[1:4])
print(cart[:2], cart[3:])
print(cart[1:99])
print(cart[-2:])
print(cart[:])📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
['우유', '계란', '빵']
['사과', '우유'] ['빵', '커피']
['우유', '계란', '빵', '커피']
['빵', '커피']
['사과', '우유', '계란', '빵', '커피']
cart[1:4]가 1번, 2번, 3번 세 칸만 가져왔습니다. 끝에 적은 4번은 들어오지 않습니다. 눈금 그림으로 돌아가면 이유가 보입니다. 눈금 1에서 눈금 4까지 자르면 그 사이에 든 칸은 셋. 그래서 끝에서 시작을 빼면 개수가 됩니다. 4 - 1은 3이고 실제로 세 칸이 나왔습니다. 이 규칙 덕에 cart[:2]와 cart[2:]처럼 같은 번호로 자르면 겹치는 칸도, 빠지는 칸도 없이 두 토막이 납니다.
시작이나 끝을 비우면 "그쪽 끝까지"입니다. cart[:2]는 처음부터 2번 앞까지, cart[3:]은 3번부터 마지막까지. 둘 다 비운 cart[:]는 전체인데, 이 표기가 잠시 뒤 복사 대목에서 한 번 더 나옵니다.
슬라이싱은 인덱스와 다르게 범위를 넘겨도 에러를 내지 않습니다. cart[5]는 멈췄지만 cart[1:99]는 있는 데까지만 조용히 잘라 옵니다. 편한 만큼 위험한 성질입니다. 잘라 온 결과가 텅 비어도 프로그램은 그냥 다음 줄로 갑니다. 6편의 조건문으로 if len(부분) > 0:처럼 한 번 묻는 습관이 여기서 쓰입니다.
8~13줄 · 넣는 둘, 빼는 둘
리스트는 만든 뒤에도 고칠 수 있습니다. 성질 표의 "바꿀 수 있다"가 이 대목입니다. 넣는 방법이 둘, 빼는 방법이 둘. 넷 다 이름 뒤에 점을 찍어 부르는 메서드입니다.
| 메서드 | 하는 일 | 돌려주는 값 | 없는 값·자리를 주면 |
|---|---|---|---|
append(값) | 맨 뒤에 붙인다 | 없음(None) | — |
insert(자리, 값) | 그 자리에 끼우고 뒤를 한 칸씩 민다 | 없음(None) | 자리가 길이를 넘으면 맨 뒤에 붙는다 |
remove(값) | 앞에서부터 찾아 처음 하나만 지운다 | 없음(None) | ValueError |
pop(자리) | 그 자리의 값을 빼서 돌려주고 없앤다. 자리를 비우면 마지막 칸 | 뺀 값 | IndexError |
cart = ["사과", "우유", "계란"]
cart.append("빵")
cart.insert(1, "바나나")
print(cart)
cart.remove("우유")
print(cart)
last = cart.pop()
first = cart.pop(0)
print(last, first, cart)
cart.remove("없는물건") # ValueError — 지우고 다시 실행해 보세요📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
['사과', '바나나', '우유', '계란', '빵']
['사과', '바나나', '계란', '빵']
빵 사과 ['바나나', '계란']
cart.append("빵") 같은 표기가 처음 나왔습니다. 이름 뒤에 점을 찍고 부르는 것이 메서드이고, "이 리스트에게 시키는 일"이라고 읽으면 됩니다. len(cart)처럼 밖에서 감싸는 함수와 달리 메서드는 대상이 앞에 옵니다.
파이썬을 대화형으로 켜 놓고 한 줄씩 쳐 보면 넷의 성격 차이가 눈에 보입니다. 값을 돌려주는 줄은 바로 아래에 답이 찍히고, 돌려주지 않는 줄은 아무것도 찍히지 않습니다.

append와 insert는 답이 없는 줄입니다. pop만 뺀 값을 돌려주고, remove에 없는 값을 주면 ValueError로 멈춥니다.
pop만 성격이 다릅니다. 값을 빼면서 그 값을 돌려주기 때문에 last = cart.pop()처럼 왼쪽에서 받아 쓸 수 있습니다. 위 출력의 빵과 사과가 그렇게 받은 값입니다. 반대로 append나 insert는 돌려주는 값이 없어서 cart = cart.append("빵")이라고 쓰면 cart가 리스트가 아니라 None으로 덮어씌워집니다. 리스트가 통째로 사라지는 실수라 이 편에서 딱 하나만 외운다면 이것을 고르겠습니다. 9편에서 함수의 "돌려주는 값"을 다룰 때 이 자리를 다시 떠올리게 됩니다.
마지막 줄은 없는 값을 지우라고 시킨 코드입니다.
ValueError: list.remove(x): x not in list
remove는 값이 없으면 이렇게 멈추고, pop은 빈 리스트에서 부르면 IndexError로 멈춥니다. 지우기 전에 그 값이 있는지 묻는 방법이 바로 다음 줄에 나옵니다.
14~19줄 · 있는지 묻고, 갈아 끼우고, 줄 세우기
in은 값이 리스트 안에 있는지 묻고 True나 False로 답합니다. index(값)은 그 값이 몇 번 칸에 있는지 알려 줍니다.
cart = ["사과", "바나나", "계란", "빵", "커피"]
print("계란" in cart, "라면" in cart)
if "빵" in cart:
print(cart.index("빵"))
cart[0] = "청사과"
print(cart)
print(sorted(cart))
print(cart.sort(), cart)📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
True False
3
['청사과', '바나나', '계란', '빵', '커피']
['계란', '바나나', '빵', '청사과', '커피']
None ['계란', '바나나', '빵', '청사과', '커피']
if "빵" in cart:로 한 번 묻고 나서 index를 불렀습니다. index도 remove처럼 없는 값을 찾으면 ValueError로 멈추기 때문입니다. 묻고 꺼내는 두 줄이 에러 하나를 막습니다. 6편에서 나누기 전에 if b == 0:으로 물었던 것과 같은 구조입니다.
cart[0] = "청사과"는 꺼내는 문법을 그대로 왼쪽에 두고 값을 넣은 것입니다. 칸 하나를 통째로 갈아 끼웁니다. 정의에서 말한 "변경 가능"이 바로 이것입니다. 문자열은 안 됩니다. word = "사과" 뒤에 word[0] = "청"이라고 쓰면 TypeError: 'str' object does not support item assignment로 멈춥니다.
정렬은 두 가지. 헷갈리면 데이터를 잃습니다. sorted(cart)는 정렬된 새 리스트를 돌려주고 원본은 그대로 둡니다. cart.sort()는 원본을 직접 줄 세우고 아무것도 돌려주지 않습니다. 위 출력 마지막 줄의 None이 그 증거입니다. cart = cart.sort()라고 쓰는 순간 정렬된 리스트가 아니라 None이 cart에 들어갑니다. 앞에서 본 cart = cart.append("빵")과 같은 종류의 사고입니다.
한글은 유니코드 번호 순으로 줄을 섭니다. 위 다섯 낱말에서는 그 결과가 가나다 순과 같게 나왔습니다. 숫자 리스트라면 작은 수부터, 영문이라면 대문자가 소문자보다 앞에 옵니다.
backup = cart 는 복사가 아니었습니다
리스트 글을 쓸 때 제가 가장 공들여 말하는 대목입니다. 원본을 남겨 두려고 backup = cart라고 적은 코드가 원본을 지키지 못합니다.
cart = ["사과", "우유"]
backup = cart
cart.append("치약")
print(backup)
print(cart is backup)
copy1 = cart[:]
copy2 = cart.copy()
cart.append("휴지")
print(copy1, copy2)
print(cart)📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
['사과', '우유', '치약']
True
['사과', '우유', '치약'] ['사과', '우유', '치약']
['사과', '우유', '치약', '휴지']
backup에 손을 댄 적이 없는데 치약이 들어 있습니다. 3편에서 =는 "오른쪽 값을 왼쪽 상자에 넣는다"였습니다. 리스트에서는 그 "값"이 서랍장 자체가 아니라 서랍장이 있는 자리입니다. 그래서 backup = cart는 서랍장을 하나 더 만드는 일이 아니라, 있던 서랍장에 이름표를 하나 더 붙이는 일입니다. 어느 이름으로 물건을 넣든 서랍장은 하나.
![위 줄에서는 backup = cart 뒤 cart.append("치약")을 하자 이름표 둘이 달린 하나의 리스트에 치약이 들어가 print(backup)에도 치약이 보이고, 아래 줄에서는 copy1 = cart[:] 뒤 cart.append("휴지")를 해도 cart와 copy1이 서로 다른 리스트라 copy1은 그대로인 과정을 단계별로 그린 흐름도](/uploads/python-list-alias.png)
위 줄은 이름표만 하나 더 붙은 경우라 backup에도 치약이 보입니다. 아래 줄은 [:]로 새 리스트를 만든 경우라 휴지는 cart에만 들어갑니다.
cart is backup이 True로 나온 것이 그 확인입니다. ==가 "값이 같은가"를 묻는다면 is는 "아예 같은 것인가"를 묻습니다.
진짜로 따로 떼어 두려면 앞에서 본 cart[:]나 cart.copy()를 씁니다. 둘 다 새 리스트를 만들어 돌려주므로, 그 뒤에 cart에 무엇을 넣어도 복사본은 그대로입니다. 위 출력의 셋째 줄과 넷째 줄이 갈라진 것이 그 결과입니다. 리스트를 넘겨받아 고치는 코드를 쓸 때 이 한 줄이 사고를 막습니다.
주석을 달고 다시 읽는 열아홉 줄
맨 위의 코드에 주석만 붙였습니다. 문법은 한 글자도 바뀌지 않았습니다.
cart = ["사과", "우유", "계란", "빵", "커피"] # 대괄호 + 쉼표 = 리스트
print(cart) # 사람이 쓴 모양 그대로 나옵니다
print(len(cart)) # 칸 수 5
print(cart[0], cart[2]) # 앞에서 0부터
print(cart[-1]) # 뒤에서 -1부터
print(cart[1:4]) # 1,2,3번 — 끝 번호 4는 빠집니다
print(cart[:2], cart[3:]) # 앞쪽만 / 뒤쪽만
cart.append("치약") # 맨 뒤에 붙이기
cart.insert(1, "바나나") # 1번 자리에 끼우기
print(cart)
cart.remove("우유") # 값으로 지우기(처음 하나)
last = cart.pop() # 마지막 칸을 빼서 받기
print(last, cart)
print("계란" in cart) # 있는지 묻기
print(cart.index("빵")) # 몇 번 칸인지 묻기
cart[0] = "청사과" # 칸 하나 갈아 끼우기
print(cart)
cart.sort() # 원본을 직접 줄 세웁니다
print(cart)📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
첫 줄이 만든 다섯 칸이 마지막 줄에서도 다섯 칸입니다. 중간에 둘이 들어오고 둘이 나갔습니다. 치약은 pop이 빼 갔고 우유는 remove가 지웠습니다. 남은 다섯 칸의 순서가 마지막에 한 번 바뀝니다.
이 열아홉 줄에서 넘어지는 자리는 정해져 있습니다. 없는 칸을 부르는 IndexError, 없는 값을 지우거나 찾는 ValueError, 돌려주는 값이 없는 메서드를 = 왼쪽에 받는 실수, 그리고 복사가 아닌 =. 처음 리스트를 쓸 때 만나기 쉬운 것들이라 그림도 그 자리마다 하나씩 두었습니다. 예제는 파이썬 3 기준이며 2026년 9월 7일 작성했습니다.
cart 하나로 본 문법 열한 개
cart = ["사과", "우유", "계란", "빵", "커피"]일 때입니다.
| 문법 | 뜻 | 예 | 결과 |
|---|---|---|---|
[값, 값, ...] | 리스트 만들기 | [] | 길이 0인 빈 리스트 |
len(cart) | 원소 개수 | len(cart) | 5 |
cart[i] | i번 칸 꺼내기(0부터) | cart[2] | '계란' |
cart[-i] | 뒤에서 i번째 | cart[-1] | '커피' |
cart[a:b] | a번부터 b번 앞까지 새 리스트 | cart[1:4] | ['우유', '계란', '빵'] |
cart[:] | 전체를 복사한 새 리스트 | copy1 = cart[:] | 따로 노는 리스트 |
cart[i] = 값 | i번 칸 갈아 끼우기 | cart[0] = "청사과" | 첫 칸이 청사과 |
값 in cart | 들어 있는지 묻기 | "계란" in cart | True |
cart.index(값) | 몇 번 칸인지 | cart.index("빵") | 3 |
sorted(cart) | 정렬한 새 리스트, 원본 유지 | sorted(cart) | 새 리스트 |
cart.sort() | 원본을 정렬, 돌려주는 값 없음 | cart.sort() | None |
한 줄만 바꾸면 출력은 어떻게 될까요
미니 퀴즈
참고 자료
정의와 동작은 파이썬 공식 문서를 기준으로 확인했습니다. 한국어 번역본입니다.
- 파이썬 자습서 3.1 — 문자열 절(3.1.2)의 "인덱스는 글자 사이를 가리킨다"는 눈금 비유와 리스트 절(3.1.3)의 대괄호 문법·인덱스·슬라이싱: https://docs.python.org/ko/3/tutorial/introduction.html#lists
- 파이썬 자습서 5.1 리스트 더 보기 — append·insert·remove·pop·index·sort·copy 메서드 정의: https://docs.python.org/ko/3/tutorial/datastructures.html#more-on-lists
- 파이썬 표준 라이브러리 "시퀀스 형 — list, tuple, range" — 변경 가능한 순서열이라는 정의와 공통 연산: https://docs.python.org/ko/3/library/stdtypes.html#lists
포켓코딩(PYTHON1) 7편 · 6편(파이썬 if 조건문)에서 이어집니다. 예제 코드는 강사 개인 GitHub 저장소의 연습 문제를 바탕으로 다시 썼습니다. 다음 편: 파이썬 for 반복문 — 슬라이싱의 끝 번호처럼, range의 끝 숫자도 포함되지 않습니다.