06. 리스트·튜플·세트·딕셔너리
- 여러 값을 묶어 담는 네 가지 그릇(리스트·튜플·세트·딕셔너리)을 구분한다.
- 각 자료구조를 만들고, 값을 꺼내고·추가·수정·삭제한다.
- 가변(mutable)과 불변(immutable)의 차이를 이해한다.
- 상황에 맞게 "무엇을 쓸지" 고를 수 있다.
왜 여러 값을 묶을까
지금까진 변수 하나에 값 하나를 담았습니다. 그런데 "반 학생 30명의 이름"을 변수 30개로 관리한다면 끔찍하겠죠. 여러 값을 하나로 묶는 그릇이 필요합니다.
Python의 대표적인 그릇은 네 가지이고, 각각 성격이 다릅니다. 먼저 전체 지도를 봅시다.
flowchart TD
Root["여러 값을 담는 그릇"]:::proc
Root --> List["📋 리스트 list<br/>[ ]<br/>순서 O · 수정 O · 중복 O"]:::data
Root --> Tuple["📌 튜플 tuple<br/>( )<br/>순서 O · 수정 X · 중복 O"]:::data
Root --> Set["🎯 세트 set<br/>{ }<br/>순서 X · 수정 O · 중복 X"]:::data
Root --> Dict["🗂️ 딕셔너리 dict<br/>{키:값}<br/>키로 조회 · 수정 O"]:::result
classDef proc fill:#7fd8d8,stroke:#2a9d8f,color:#14532d
classDef data fill:#a8dadc,stroke:#457b9d,color:#1d3557
classDef result fill:#b8e6c1,stroke:#34a853,color:#14532d
한눈에 비교하면 이렇습니다.
| 그릇 | 기호 | 순서 | 수정 가능? | 중복 허용? | 한 줄 요약 |
|---|---|---|---|---|---|
리스트 list | [ ] | 있음 | ✅ 가능 | ✅ | 가장 많이 쓰는 만능 목록 |
튜플 tuple | ( ) | 있음 | ❌ 불가 | ✅ | 바뀌면 안 되는 묶음 |
세트 set | { } | 없음 | ✅ 가능 | ❌ | 중복 없는 모음 |
딕셔너리 dict | {키:값} | 있음 | ✅ 가능 | 키 중복 ❌ | 이름표(키)로 찾는 사전 |
📋 리스트 (list)
가장 많이 쓰는 자료구조입니다. 대괄호 [ ]에 값을 쉼표로 나열합니다. 장바구니에 물건을 순서대로 담는다고 생각하면 됩니다.
fruits = ["사과", "배", "감"] print(fruits) # ['사과', '배', '감'] print(len(fruits)) # 3
값 꺼내기 (인덱싱·슬라이싱)
문자열과 똑같이 0부터 시작하는 인덱스로 꺼냅니다.
fruits = ["사과", "배", "감"] print(fruits[0]) # 사과 (첫 번째) print(fruits[-1]) # 감 (마지막) print(fruits[0:2]) # ['사과', '배'] (슬라이싱, 끝 미포함)
추가·수정·삭제
리스트는 수정 가능(mutable)합니다. 만든 뒤에도 내용을 바꿀 수 있습니다.
fruits = ["사과", "배", "감"] fruits.append("귤") # 맨 뒤에 추가 print(fruits) # ['사과', '배', '감', '귤'] fruits[0] = "딸기" # 0번 값 수정 print(fruits) # ['딸기', '배', '감', '귤'] fruits.remove("감") # 값으로 삭제 print(fruits) # ['딸기', '배', '귤']
자주 쓰는 리스트 메서드입니다.
| 메서드 | 하는 일 |
|---|---|
.append(x) | 맨 뒤에 x 추가 |
.insert(i, x) | i번 위치에 x 삽입 |
.remove(x) | 값이 x인 첫 항목 삭제 |
.pop() | 맨 뒤 항목을 꺼내며 삭제 |
.sort() | 정렬 (원본을 바꿈) |
.reverse() | 순서 뒤집기 |
x in 리스트 | 포함 여부 (True/False) |
nums = [3, 1, 2] nums.sort() print(nums) # [1, 2, 3] print(2 in nums) # True
```python
fruits = ["사과", "배"]
print(fruits[5])
```
```text
IndexError: list index out of range
```
IndexError는 "그 번호는 범위 밖이다"라는 뜻입니다. 항목이 2개면 유효한 인덱스는 0과 1뿐입니다.📌 튜플 (tuple)
튜플은 수정할 수 없는 리스트라고 생각하면 됩니다. 소괄호 ( )로 만듭니다.
point = (3, 5) print(point[0]) # 3 print(point[1]) # 5
리스트와 거의 같지만, 한 번 만들면 바꿀 수 없습니다(불변, immutable).
point = (3, 5) point[0] = 9 # ❌ 에러!
TypeError: 'tuple' object does not support item assignment
"바꿀 수 없는 게 무슨 장점이지?"싶을 수 있습니다. 바로 그 점이 장점입니다. 실수로 바뀌면 안 되는 값(좌표, 색상 RGB값, 요일 등)을 튜플로 만들면 안전합니다.
RGB_RED = (255, 0, 0) # 빨강은 영원히 (255, 0, 0) WEEKDAYS = ("월", "화", "수", "목", "금")
언패킹: 튜플의 진짜 매력
튜플(과 리스트)은 여러 변수에 한 번에 풀어 담을 수 있습니다. 이를 언패킹(unpacking)이라 합니다.
point = (3, 5) x, y = point # x에 3, y에 5가 한 번에! print(x, y) # 3 5
이 문법 덕분에 두 변수의 값을 맞바꾸는 것도 한 줄로 끝납니다 — 아주 파이썬다운 표현입니다.
a = 1 b = 2 a, b = b, a # 값을 동시에 맞바꿈 print(a, b) # 2 1
a, b = b, a 한 줄입니다. 8장 반복문에서 이 언패킹이 또 등장합니다.🎯 세트 (set)
세트는 중복이 없는 모음입니다. 중괄호 { }로 만듭니다. 순서가 없어서 인덱스로 꺼낼 수는 없습니다.
nums = {1, 2, 2, 3, 3, 3}
print(nums) # {1, 2, 3} ← 중복이 저절로 사라짐!
세트의 가장 흔한 쓰임: 중복 제거
리스트에서 중복을 없애고 싶을 때, set()으로 바꿨다가 다시 list()로 되돌리는 것이 정석입니다.
dup = [1, 1, 2, 3, 3, 3] unique = list(set(dup)) print(unique) # [1, 2, 3]
집합 연산
수학의 집합처럼 교집합·합집합·차집합을 구할 수 있습니다.
a = {1, 2, 3}
b = {2, 3, 4}
print(a & b) # {2, 3} 교집합 (둘 다 있는 것)
print(a | b) # {1, 2, 3, 4} 합집합 (전부 합치기)
print(a - b) # {1} 차집합 (a에만 있는 것)
flowchart LR
subgraph A["세트 a"]
direction TB
A1["1"]
end
subgraph Both["교집합 a & b"]
I1["2, 3"]
end
subgraph B["세트 b"]
B1["4"]
end
A -.합집합 a or b.-> Both -.-> B
classDef default fill:#a8dadc,stroke:#457b9d,color:#1d3557
| 연산 | 기호 | 의미 |
|---|---|---|
| 교집합 | a & b | 양쪽 모두에 있는 원소 |
| 합집합 | `a \ | b` |
| 차집합 | a - b | a에는 있고 b에는 없는 원소 |
in) 확인도 리스트보다 세트가 훨씬 빠릅니다.🗂️ 딕셔너리 (dict)
딕셔너리는 이름 그대로 사전입니다. 단어(키)를 찾으면 뜻(값)이 나오죠. 키(key)와 값(value)을 짝지어 저장합니다.
person = {
"name": "민지",
"age": 25,
"city": "서울",
}
print(person["name"]) # 민지 ← 키로 값을 꺼냄
print(person["age"]) # 25
리스트가 번호(인덱스)로 값을 찾는다면, 딕셔너리는 이름(키)으로 값을 찾습니다. "0번, 1번"보다 "name, age"가 훨씬 의미가 분명하죠.
추가·수정·삭제·조회
person = {"name": "민지", "age": 25}
person["age"] = 26 # 기존 키 → 수정
person["city"] = "서울" # 새 키 → 추가
print(person) # {'name': '민지', 'age': 26, 'city': '서울'}
print("name" in person) # True ← 키가 있는지 확인
```python
print(person["phone"])
```
```text
KeyError: 'phone'
```
KeyError는 "그런 키가 없다"는 뜻입니다. 이를 피하려면 .get()을 쓰세요. .get()은 키가 없으면 에러 대신 기본값을 돌려줍니다.```python
print(person.get("phone", "없음")) # 없음 (에러 안 남)
```
키·값 전체 다루기
person = {"name": "민지", "age": 26}
print(person.keys()) # dict_keys(['name', 'age'])
print(person.values()) # dict_values(['민지', 26])
print(person.items()) # dict_items([('name', '민지'), ('age', 26)])
.items()는 8장 반복문에서 "키와 값을 동시에 훑는" 용도로 다시 만납니다. (앞서 본 언패킹과 결합됩니다!)
for key, value in person.items(): print(f"{key} → {value}") # name → 민지 # age → 26
가변(mutable) vs 불변(immutable) 정리
이 장에서 계속 나온 핵심 개념을 정리합시다. 만든 뒤 내용을 바꿀 수 있으면 가변, 못 바꾸면 불변입니다.
| 자료형 | 가변/불변 |
|---|---|
리스트 list | 가변 (mutable) |
딕셔너리 dict | 가변 |
세트 set | 가변 |
튜플 tuple | 불변 (immutable) |
문자열 str | 불변 |
숫자 int/float | 불변 |
s.upper()는 원본 s를 바꾸지 않고 새 문자열을 돌려줍니다. 결과를 쓰려면 s = s.upper()처럼 다시 담아야 합니다. (가변/불변의 더 깊은 동작은 중급편에서 다룹니다.)무엇을 언제 쓸까? (선택 가이드)
flowchart TD
Q1{"키(이름)로<br/>값을 찾고 싶다?"}:::proc
Q1 -->|예| Dict["🗂️ 딕셔너리"]:::result
Q1 -->|아니오| Q2{"중복을 자동으로<br/>없애고 싶다?"}:::proc
Q2 -->|예| Set["🎯 세트"]:::result
Q2 -->|아니오| Q3{"나중에 내용이<br/>바뀔 수 있다?"}:::proc
Q3 -->|예| List["📋 리스트"]:::result
Q3 -->|아니오, 고정| Tuple["📌 튜플"]:::result
classDef proc fill:#fff3b0,stroke:#e0a800,color:#5c4500
classDef result fill:#b8e6c1,stroke:#34a853,color:#14532d
- 리스트: 가장 기본. 순서가 있고 바뀌는 목록 (할 일 목록, 점수들)
- 튜플: 바뀌면 안 되는 고정된 묶음 (좌표, RGB)
- 세트: 중복 없는 모음, 빠른 포함 검사 (방문한 페이지, 태그)
- 딕셔너리: 이름표로 찾는 데이터 (사용자 정보, 설정값)
이 장에서 배운 것
- 여러 값을 담는 네 그릇: 리스트
[]·튜플()·세트{}·딕셔너리{키:값}. - 리스트는 가장 만능.
.append()·[i]=·.remove()로 추가·수정·삭제하고 인덱싱·슬라이싱으로 꺼낸다. - 튜플은 불변이라 안전하다. 언패킹(
x, y = point,a, b = b, a)이 강력하다. - 세트는 중복 자동 제거와 집합 연산(
&,|,-)에 쓴다. - 딕셔너리는 키로 값을 조회한다. 없는 키는
KeyError, 안전하게는.get(키, 기본값). - 리스트·딕셔너리·세트는 가변, 튜플·문자열·숫자는 불변이다.
🧪 실습 문제
문제 1. 리스트 colors = ["빨강", "초록", "파랑"]에 "노랑"을 맨 뒤에 추가하고, "초록"을 삭제한 뒤 전체를 출력하세요.
문제 2. 다음 코드의 출력은? 왜 그런지도 설명해 보세요.
nums = [5, 3, 5, 1, 3, 5] print(len(set(nums)))
문제 3. 딕셔너리 book = {"title": "파이썬 입문", "pages": 300}에서 (a) "title" 값을 출력하고, (b) .get()을 이용해 없는 키 "author"를 "미상"이라는 기본값으로 출력하세요.
문제 4. 좌표 튜플 pos = (10, 20)을 언패킹해 x, y에 각각 담은 뒤 x좌표=10, y좌표=20 형태로 출력하세요.
문제 5. (생각해보기) 다음 중 튜플로 만드는 게 더 적절한 것은? 리스트가 더 적절한 것은?
- (a) 한 주의 요일 이름들
- (b) 사용자가 장바구니에 담는 상품들
- (c) 화면 해상도
(1920, 1080)
<details>
<summary>✅ 정답·해설 보기</summary>
1.
colors = ["빨강", "초록", "파랑"] colors.append("노랑") colors.remove("초록") print(colors) # ['빨강', '파랑', '노랑']
2. 3. set(nums)이 중복을 없애 {1, 3, 5}(원소 3개)가 되고, len()이 3을 반환합니다. "서로 다른 값이 몇 개인가"를 셀 때 쓰는 흔한 기법입니다.
3.
book = {"title": "파이썬 입문", "pages": 300}
print(book["title"]) # 파이썬 입문
print(book.get("author", "미상")) # 미상
4.
pos = (10, 20) x, y = pos print(f"x좌표={x}, y좌표={y}") # x좌표=10, y좌표=20
5.
- (a) 튜플 — 요일은 고정되어 바뀌지 않음
- (b) 리스트 — 담고 빼는 등 계속 바뀜
- (c) 튜플 — 해상도는 하나의 고정된 묶음
</details>
◀️ 이전 장: 05. 불리언과 비교 | ▶️ 다음 장: 07. 조건문