리스트(list)는 값 여럿을 차례로 담은 값입니다. 자리 번호로 값을 꺼내고 append()로 끝에 값을 더하며, 이름 둘이 한 리스트를 가리키면 한쪽 이름으로 바꾼 것이 다른 쪽 이름으로도 보입니다.
주문이 몇 개일지 미리 모르면 주문마다 이름을 지어 둘 수 없습니다. 리스트 하나에 주문을 모두 담고 이름 하나를 붙이면 됩니다. 그런데 리스트는 수나 문자열과 달리 만든 뒤에도 바뀌는 값입니다. 이것을 모르면 이름 둘이 한 리스트를 가리킬 때, 손대지 않은 이름의 리스트가 저절로 바뀐 것처럼 보입니다. 이 레슨에서는 이름표 규칙(규칙 3)을 리스트에서 다시 봅니다.
이 단원(리스트와 튜플)을 이미 안다면 단원 연습 문제부터 풀고 틀린 레슨만 보세요.
1리스트를 만들고 꺼내기
대괄호 안에 값을 쉼표로 나열하면 리스트가 하나 만들어집니다.
orders = ['커피', '라테', '녹차']
print(orders)
print(orders[0])
print(orders[-1])
print(len(orders))
['커피', '라테', '녹차']
커피
녹차
3리스트를 통째로 찍으면 대괄호와 쉼표, 문자열의 따옴표까지 찍힙니다. 쉼표 뒤에는 빈칸 하나, 문자열은 큰따옴표로 썼어도 보통 작은따옴표로 찍힙니다. 칸 하나를 꺼내 찍으면 따옴표 없이 그 값만 찍힙니다. 결과를 쓸 때도 이 꼴 그대로 씁니다.
리스트의 칸에도 문자열의 글자처럼 0부터 자리 번호가 붙고, 꺼내는 법도 인덱스와 자르기와 같습니다. orders[-1]은 마지막 칸이고, orders[0:2]처럼 자르면 앞 두 칸을 담은 새 리스트가 만들어집니다. len()은 칸 수를 셉니다.
리스트에 든 값을 자료에 따라 요소(element)나 항목(item)이라고도 부릅니다. 칸이 하나도 없는 빈 리스트는 []로 씁니다.
2이름 둘이 한 리스트를 가리킨다
그림의 코드입니다. append()는 리스트 끝에 값 하나를 더하는 메서드입니다.
orders = ['커피', '라테']
today = orders
today.append('쿠키')
print(orders)
['커피', '라테', '쿠키']2번 줄 today = orders는 오른쪽 orders를 계산해 orders가 가리키는 리스트를 얻고, 이름 today를 바로 그 리스트에 붙입니다(규칙 2). 새 리스트는 만들지 않습니다. 그래서 이름은 둘이고 리스트는 하나입니다(규칙 3).
3번 줄은 today가 가리키는 리스트 끝에 '쿠키'를 더합니다. 리스트를 새로 만들지 않고 그 리스트를 제자리에서(in place) 바꿉니다.
4번 줄의 orders도 같은 리스트를 가리키므로 칸 셋이 다 찍힙니다. 이름표 다시 붙이기에서 미뤄 둔 장면이 이것입니다.
이름이 값을 가리키는 것을 자료에 따라 참조(reference)라고도 부르고, today처럼 한 값에 붙은 또 하나의 이름을 별칭(alias)이라고 합니다.
그림은 리스트를 이름 칸 밖에 따로 그리고 머리에 꼬리표 ①을 붙입니다. 꼬리표가 같으면 같은 리스트입니다. 칸 안의 '커피' 같은 값은 칸에 바로 적었습니다. 정확히는 칸도 값을 가리키지만, 수와 문자열은 바꿀 수 없는 값이라 이렇게 줄여 적어도 결과가 같습니다.
3다시 붙이면 그 이름만 옮겨 간다
2절 코드의 3번 줄을 today = ['쿠키']로 바꾸고, 끝에 print(today)를 더했습니다. 무엇이 찍힐까요?
orders = ['커피', '라테']
today = orders
today = ['쿠키']
print(orders)
print(today)
실행 결과 보기
['커피', '라테']
['쿠키']예상과 다르면 그곳이 배울 곳입니다. 3번 줄은 리스트를 바꾸지 않습니다. 새 리스트 ['쿠키']를 만들고 이름 today만 그 리스트로 옮겨 붙입니다. orders는 처음 리스트에 그대로 붙어 있어 ['커피', '라테']를 찍습니다(규칙 3).
| 3번 줄 | 하는 일 | orders로 보면 |
|---|---|---|
today.append('쿠키') | 같은 리스트를 제자리에서 바꾼다 | 바뀌어 있다 |
today = ['쿠키'] | 새 리스트에 today만 다시 붙인다 | 그대로다 |
예제
마지막 주문 꺼내기
마지막 주문을 꺼내려고 칸 수 len(orders)를 자리 번호로 썼습니다.
orders = ['커피', '라테', '녹차']
print(orders[len(orders)])
Traceback (most recent call last): File "main.py", line 2, in <module> print(orders[len(orders)]) ~~~~~~^^^^^^^^^^^^^IndexError: list index out of range맨 아래 줄은 '리스트의 자리 번호가 범위를 벗어났다'는 뜻입니다. 칸 수는 3이지만 번호는 0부터라 0, 1, 2뿐입니다. 마지막 칸은 orders[len(orders) - 1], 더 짧게는 orders[-1]로 꺼냅니다.
자주 틀리는 곳
틀린 생각: b = a를 하면 b는 a가 가리키는 리스트의 사본을 받는다.
수에서는 b = a 뒤에 a를 다시 붙여도 b가 그대로였습니다. 그래서 b가 사본을 받은 것처럼 보이지만, b = a는 같은 값에 이름을 하나 더 붙일 뿐입니다.
a = [1, 2]
b = a
b.append(3)
print(a)
[1, 2, 3]b로 더한 3이 a로 봐도 보입니다.
맞는 규칙: b = a는 새 리스트를 만들지 않고 a가 가리키는 리스트에 이름 b를 하나 더 붙입니다. 그래서 한 이름으로 리스트를 바꾸면 다른 이름으로도 보입니다(규칙 3).
틀린 생각: 두 이름 가운데 하나를 새 리스트에 다시 붙이면 다른 이름도 따라 옮겨 간다.
한쪽 이름으로 바꾼 것이 다른 쪽에도 보이니, 다시 붙이기도 함께 일어날 것 같습니다. 그러나 다시 붙이기는 리스트를 바꾸지 않습니다.
a = [1, 2]
b = a
b = [3]
print(a)
[1, 2]3번 줄은 새 리스트 [3]을 만들고 b만 그 리스트로 옮겨 붙입니다. a가 가리키는 [1, 2]는 아무도 바꾸지 않았습니다.
맞는 규칙: 다시 붙이기는 그 이름 하나만 새 값으로 옮길 뿐 리스트를 바꾸지 않습니다. 다른 이름으로도 보이는 것은 append()처럼 리스트를 제자리에서 바꾼 때뿐입니다(규칙 3).
확인 문제
1. 2절 코드의 4번 줄을 print(orders[-1])로 바꿨습니다. 무엇이 찍힐까요?
orders = ['커피', '라테']
today = orders
today.append('쿠키')
print(orders[-1])
힌트
2번 줄 뒤 today와 orders가 각각 어느 리스트를 가리키는지 먼저 그려 봅니다.
정답
쿠키2번 줄에서 today가 orders와 같은 리스트에 붙고, 3번 줄이 그 리스트 끝에 '쿠키'를 더합니다. orders로 봐도 마지막 칸은 '쿠키'입니다.
흔한 오답은 라테입니다. today가 사본을 받아 orders는 그대로라고 본 것입니다(복사된다는 생각). today = orders는 같은 리스트에 이름을 하나 더 붙입니다(규칙 3).
2. 실행 결과가 아래 두 줄이 되도록 ㉠~㉤을 위에서 아래로 놓으세요.
['커피', '라테', '쿠키']
['커피', '라테', '쿠키']
- ㉠
print(orders) - ㉡
today.append('쿠키') - ㉢
today = orders - ㉣
orders = ['커피', '라테'] - ㉤
print(today)
힌트
놓아 본 차례대로 줄마다 이름표를 그리고, 리스트가 몇 개 생기는지 셉니다.
놓은 뒤 물음
놓은 차례에서 ㉢이 ㉡보다 위에 오는 까닭은 무엇일까요?
- ① ㉢으로
today가orders와 같은 리스트에 붙어 있어야, ㉡이 그 리스트에 '쿠키'를 더하기 때문 - ② ㉢이
orders의 사본을 만들어 두어야, ㉡이 '쿠키'를 더할 리스트가 생기기 때문 - ③ ㉢이 이름
today를 이름orders에 묶어 두어야,today에 일어난 일이orders에도 일어나기 때문
정답
㉣ ㉢ ㉡ ㉠ ㉤ 차례이고, 까닭은 ①입니다.
orders = ['커피', '라테']
today = orders
today.append('쿠키')
print(orders)
print(today)['커피', '라테', '쿠키']
['커피', '라테', '쿠키']㉠과 ㉤은 같은 리스트를 찍으므로 ㉣ ㉢ ㉡ ㉤ ㉠으로 바꿔 놓아도 맞습니다.
- ② 사본은 생기지 않습니다. ㉢은 같은 리스트에 이름을 하나 더 붙일 뿐이고, 사본이었다면 ㉠은
['커피', '라테']를 찍습니다(복사된다는 생각). - ③ 이름끼리 묶이지 않습니다. 두 이름이 한 리스트를 가리킬 뿐이라,
today를 새 리스트에 다시 붙이면orders는 따라가지 않습니다(규칙 3).
3. 장보기 목록을 두 이름으로 다루는 코드입니다. 무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.
cart = ['우유', '빵']
mine = cart
cart = ['사과']
mine.append('달걀')
print(cart)
print(mine)
힌트
줄마다 이름표를 다시 그려, 5번 줄과 6번 줄에 왔을 때 cart와 mine이 각각 어느 리스트를 가리키는지 봅니다.
정답
['사과']
['우유', '빵', '달걀']2번 줄에서 mine이 cart와 같은 리스트 ['우유', '빵']에 붙습니다. 3번 줄은 cart만 새 리스트 ['사과']로 옮겨 붙이고, mine은 처음 리스트에 그대로 붙어 있습니다. 4번 줄은 mine이 가리키는 처음 리스트에 '달걀'을 더합니다.
흔한 오답은 두 줄 모두 ['사과', '달걀']입니다. 3번 줄에서 mine도 cart를 따라 새 리스트로 옮겨 간다고 본 것입니다. 다시 붙이기는 그 이름 하나만 옮깁니다(규칙 3).
아래 코드 3번 줄 today.append('쿠키')를 today = today + ['쿠키']로 바꾸면 4번 줄이 무엇을 찍는지 봅니다.
처음 펼 때 약 6MB를 받습니다.컴퓨터에서 해 보기
파이썬 3.14. Tab을 누르면 다음 단추나 칸으로 갑니다. 들여쓰기는 빈칸 네 개입니다. Enter는 앞줄 들여쓰기를 잇고, 콜론 뒤에서는 한 단계 더 들여 씁니다. Ctrl+Enter로 실행합니다.
'실행'을 누르면 여기에 나옵니다.
여기서 쓴 코드 · 내 예상은 저장하지도 운영자에게 보내지도 않습니다. 페이지를 새로 열면 처음 코드입니다.