07 / 15 Python 공부 시리즈 — 컬렉션 자료형
← 6편: 함수(Function) 완전 정복 보러 가기
Python 공부 시리즈 · 7편 | list · tuple · dict · set · comprehension
파이썬(Python) 공부 7편
리스트·튜플·딕셔너리·집합 완전 정복
파이썬에는 여러 데이터를 묶어서 관리하는 네 가지 컬렉션 자료형이 있습니다. 리스트·튜플·딕셔너리·집합은 각각 특성이 다르기 때문에 상황에 맞게 골라 쓰는 것이 중요합니다. 메서드 총정리부터 컴프리헨션까지 한 번에 정리합니다.
list — 순서O 중복O 변경O tuple — 순서O 불변 dict — 키-값 쌍 set — 중복X 집합연산 컴프리헨션
📊 4가지 컬렉션 — 한눈에 비교
list 리스트 [ ]
순서 O / 중복 O / 변경 O
가장 자주 쓰이는 자료형.
인덱스로 접근, 추가·삭제·수정 모두 가능.
예: [1, 2, 3, "python"]
tuple 튜플 ( )
순서 O / 중복 O / 변경 X (불변)
한 번 만들면 수정 불가. 리스트보다 빠름.
좌표, 고정 데이터, 함수 반환값에 사용.
예: (10, 20, "Seoul")
dict 딕셔너리 { }
키-값(key-value) 쌍 / 키는 고유
키로 빠르게 값 조회. Python 3.7+부터 삽입 순서 유지.
JSON 데이터 처리에 필수.
예: {"name": "Alice", "age": 25}
set 집합 { }
순서 X / 중복 X / 집합 연산 O
중복 제거, 교집합·합집합·차집합 연산에 사용.
인덱스 접근 불가.
예: {1, 2, 3, 4}
📝 list — 리스트 완전 정복
# 리스트 생성
nums = [1, 2, 3, 4, 5]
mixed = [1, "hello", True, 3.14] # 다양한 타입 혼합 가능
nested = [[1, 2], [3, 4], [5, 6]] # 중첩 리스트
empty = [] # 빈 리스트
# 인덱싱·슬라이싱 (3편 문자열과 동일한 방식)
print(nums[0]) # 1
print(nums[-1]) # 5
print(nums[1:4]) # [2, 3, 4]
print(nums[::-1]) # [5, 4, 3, 2, 1] (뒤집기)
# 값 수정
nums[0] = 10
print(nums) # [10, 2, 3, 4, 5]
# 중첩 리스트 접근
print(nested[1][0]) # 3 (두 번째 리스트의 첫 번째 요소)
🔨 리스트 메서드 총정리
| 메서드 | 설명 | 예시 / 결과 |
|---|---|---|
| append(x) | 맨 끝에 요소 추가 | lst.append(6) |
| insert(i, x) | i번 위치에 x 삽입 | lst.insert(0, 99) |
| extend(iter) | 다른 반복가능 객체 이어붙이기 | lst.extend([7,8]) |
| remove(x) | 값 x 첫 번째 항목 삭제 | lst.remove(3) |
| pop(i=-1) | i번 요소 꺼내며 삭제 (기본 마지막) | lst.pop() → 마지막값 |
| index(x) | x의 첫 번째 인덱스 반환 | lst.index(3) → 2 |
| count(x) | x 등장 횟수 | lst.count(2) → 1 |
| sort() | 제자리 정렬 (원본 변경) | lst.sort(reverse=True) |
| sorted(lst) | 정렬된 새 리스트 반환 (원본 유지) | sorted(lst) |
| reverse() | 제자리 역순 (원본 변경) | lst.reverse() |
| copy() | 얕은 복사본 반환 | new = lst.copy() |
| clear() | 모든 요소 삭제 | lst.clear() → [] |
lst = [3, 1, 4, 1, 5, 9, 2]
lst.append(6) # [3,1,4,1,5,9,2,6]
lst.insert(0, 0) # [0,3,1,4,1,5,9,2,6]
lst.remove(1) # 첫 번째 1 삭제 → [0,3,4,1,5,9,2,6]
popped = lst.pop() # 6 꺼내기 → [0,3,4,1,5,9,2]
print(popped) # 6
lst.sort() # [0,1,2,3,4,5,9] (원본 변경)
print(sorted(lst, reverse=True)) # [9,5,4,3,2,1,0] (원본 유지)
# del 키워드로도 삭제 가능
fruits = ["apple", "banana", "cherry"]
del fruits[1] # banana 삭제
print(fruits) # ['apple', 'cherry']
# 리스트 연결과 반복
a = [1, 2]
b = [3, 4]
print(a + b) # [1, 2, 3, 4]
print(a * 3) # [1, 2, 1, 2, 1, 2]
⚠️ 얕은 복사(Shallow Copy) vs 깊은 복사(Deep Copy)
- b = a → 같은 객체를 가리킴 / a 변경 시 b도 변경됨
- b = a.copy() 또는 b = a[:] → 얕은 복사 / 1단계 요소는 독립, 중첩 리스트는 공유
- import copy; b = copy.deepcopy(a) → 깊은 복사 / 완전히 독립된 복사
🔒 tuple — 튜플 완전 정복
# 튜플 생성 — 소괄호 또는 괄호 없이도 가능
t1 = (1, 2, 3)
t2 = 1, 2, 3 # 괄호 없이도 튜플
t3 = (42,) # 요소 하나짜리 튜플 — 쉼표 필수!
t4 = (42) # ← 이건 튜플 아닌 그냥 정수 42
# 인덱싱·슬라이싱 — 리스트와 동일
print(t1[0]) # 1
print(t1[1:3]) # (2, 3)
# 튜플은 수정 불가 → TypeError
# t1[0] = 100 ← TypeError!
# 튜플 언패킹 — 함수 반환값 받을 때 자주 사용
x, y, z = t1
print(x, y, z) # 1 2 3
# * 연산자로 나머지 모아받기
first, *rest = (1, 2, 3, 4, 5)
print(first) # 1
print(rest) # [2, 3, 4, 5]
# 두 변수 값 스왑 — 튜플 언패킹 활용
a, b = 10, 20
a, b = b, a # temp 변수 없이 스왑!
print(a, b) # 20 10
# 리스트 ↔ 튜플 변환
lst = list(t1) # 튜플 → 리스트
tup = tuple(lst) # 리스트 → 튜플
💡
튜플 vs 리스트 선택 기준 변경이 필요 없는 데이터라면 튜플을 사용하자
- 튜플 사용 시: 변경되면 안 되는 데이터 (좌표, 설정값, DB 레코드) / 딕셔너리의 키로 사용할 때 (리스트는 키 불가) / 함수에서 여러 값 반환 시
- 리스트 사용 시: 요소를 추가·삭제·수정해야 할 때 / 순서가 중요한 일반적인 목록
- 성능: 튜플이 리스트보다 생성 속도가 약간 빠르고 메모리를 적게 씀
🔑 dict — 딕셔너리 완전 정복
# 딕셔너리 생성
person = {"name": "Alice", "age": 25, "city": "Seoul"}
empty_d = {} # 빈 딕셔너리
d2 = dict(name="Bob", age=30) # dict() 생성자
# 값 접근
print(person["name"]) # Alice
print(person.get("age")) # 25
print(person.get("email")) # None (키 없어도 오류 없음)
print(person.get("email", "없음")) # 없음 (기본값 지정)
# person["email"] → KeyError!
# 추가·수정
person["email"] = "alice@example.com" # 새 키 추가
person["age"] = 26 # 기존 값 수정
# 삭제
del person["city"] # 키-값 삭제
age = person.pop("age") # 꺼내며 삭제 → age=26
# 키/값/항목 순회
for key in person.keys(): # 키만
print(key)
for val in person.values(): # 값만
print(val)
for k, v in person.items(): # 키+값 동시
print(f"{k}: {v}")
🔨 딕셔너리 유용한 메서드
| 메서드 | 설명 | 반환값 |
|---|---|---|
| get(key, default) | 키로 값 조회 (없으면 default) | 값 or None |
| keys() | 모든 키 뷰 반환 | dict_keys |
| values() | 모든 값 뷰 반환 | dict_values |
| items() | 모든 키-값 쌍 뷰 | dict_items |
| pop(key) | 키 꺼내며 삭제 | 값 |
| update(dict2) | 다른 딕셔너리로 업데이트 | None |
| setdefault(key, val) | 키 없을 때만 기본값 설정 | 값 |
| copy() | 얕은 복사 | dict |
# update — 여러 키 한 번에 업데이트 / 병합
d1 = {"a": 1, "b": 2}
d2 = {"b": 99, "c": 3}
d1.update(d2)
print(d1) # {'a': 1, 'b': 99, 'c': 3}
# 딕셔너리 병합 (Python 3.9+) — | 연산자
merged = {"a": 1} | {"b": 2}
print(merged) # {'a': 1, 'b': 2}
# in 연산자 — 키 존재 여부 확인
person = {"name": "Alice", "age": 25}
print("name" in person) # True
print("email" in person) # False
# setdefault — 없을 때만 기본값 추가 (있으면 그대로)
person.setdefault("city", "Seoul")
person.setdefault("name", "Unknown") # name 있으므로 변경 안 됨
🔁 set — 집합 완전 정복
# 집합 생성 — 중복 자동 제거
s1 = {1, 2, 3, 3, 2}
print(s1) # {1, 2, 3} (중복 제거, 순서 보장 X)
s2 = set([1, 1, 2, 3]) # 리스트에서 집합 생성
empty_s = set() # 빈 집합 — {} 쓰면 딕셔너리!
# 활용: 리스트 중복 제거
nums = [1, 2, 2, 3, 3, 3]
unique = list(set(nums))
print(unique) # [1, 2, 3] (순서 보장 안 됨)
# 집합 연산 — 핵심 기능
A = {1, 2, 3, 4}
B = {3, 4, 5, 6}
print(A | B) # {1,2,3,4,5,6} 합집합 (union)
print(A.union(B)) # 동일
print(A & B) # {3, 4} 교집합 (intersection)
print(A.intersection(B)) # 동일
print(A - B) # {1, 2} 차집합 (difference)
print(A.difference(B)) # 동일
print(A ^ B) # {1,2,5,6} 대칭차집합
# 포함 관계
print({1, 2}.issubset(A)) # True ({1,2} ⊆ A)
print(A.issuperset({1, 2})) # True (A ⊇ {1,2})
print(A.isdisjoint({5, 6})) # True (공통 요소 없음)
# 요소 추가·삭제
s1.add(10) # 요소 하나 추가
s1.update([20, 30]) # 여러 요소 추가
s1.remove(1) # 삭제 (없으면 KeyError)
s1.discard(999) # 삭제 (없어도 오류 없음)
⚡ 컴프리헨션 — 한 줄로 컬렉션 만들기
컴프리헨션은 for문을 한 줄로 압축해 새 컬렉션을 생성하는 파이썬만의 강력한 문법입니다. 리스트·딕셔너리·집합 모두 지원합니다.
# ① 리스트 컴프리헨션 [표현식 for 변수 in 반복객체 if 조건]
squares = [x ** 2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
evens = [x for x in range(20) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# 조건부 표현식 포함 (삼항 연산자와 조합)
labels = ["짝수" if x % 2 == 0 else "홀수" for x in range(5)]
print(labels) # ['짝수', '홀수', '짝수', '홀수', '짝수']
# 중첩 컴프리헨션 (2차원 리스트 평탄화)
matrix = [[1,2,3],[4,5,6],[7,8,9]]
flat = [n for row in matrix for n in row]
print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# ② 딕셔너리 컴프리헨션 {키: 값 for ...}
sq_dict = {x: x**2 for x in range(1, 6)}
print(sq_dict) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
words = ["apple", "banana", "cherry"]
len_dict = {w: len(w) for w in words}
print(len_dict) # {'apple': 5, 'banana': 6, 'cherry': 6}
# ③ 집합 컴프리헨션 {표현식 for ...}
sq_set = {x**2 for x in [1,2,3,2,1]}
print(sq_set) # {1, 4, 9} (중복 제거)
# ④ 제너레이터 표현식 (괄호) — 메모리 효율적
gen = (x**2 for x in range(10))
print(sum(gen)) # 285 (한 번에 생성 안 하고 필요할 때만)
📝 7편 실습 문제
실습 1 — 단어 빈도 카운터 (딕셔너리)
- 문장을 단어로 분리해 각 단어의 등장 횟수를 딕셔너리로 만들기
- 예: "apple banana apple cherry banana apple" → {'apple': 3, 'banana': 2, 'cherry': 1}
- 힌트: setdefault 또는 get 활용 / 딕셔너리 컴프리헨션도 가능
실습 2 — 공통 원소 찾기 (집합)
- 두 반의 수강생 리스트에서 두 반 모두 수강한 학생 출력 (교집합)
- 어느 한 반에서만 수강한 학생 출력 (대칭차집합)
# 실습 1 — 단어 빈도 카운터
sentence = "apple banana apple cherry banana apple"
words = sentence.split()
# 방법 A: 딕셔너리 직접 구성
counter = {}
for w in words:
counter[w] = counter.get(w, 0) + 1
print(counter) # {'apple': 3, 'banana': 2, 'cherry': 1}
# 방법 B: collections.Counter (표준 라이브러리)
from collections import Counter
print(Counter(words)) # Counter({'apple': 3, 'banana': 2, 'cherry': 1})
# 실습 2 — 집합 연산
class_a = {"Alice", "Bob", "Carol", "Dave"}
class_b = {"Bob", "Dave", "Eve", "Frank"}
print("두 반 모두:", class_a & class_b) # {'Bob', 'Dave'}
print("한 반만:", class_a ^ class_b) # {'Alice','Carol','Eve','Frank'}
7편 핵심 요약
- list [ ]: 순서O 중복O 변경O / append·insert·remove·pop·sort·copy / 슬라이싱 지원
- tuple ( ): 순서O 중복O 변경X(불변) / 언패킹 / a,b=b,a 스왑 / 딕셔너리 키로 사용 가능
- dict { }: 키-값 쌍 / Python 3.7+ 삽입 순서 유지 / get()으로 안전하게 조회 / items()로 순회
- set { }: 순서X 중복X / 빈 집합은 set() / 합집합|·교집합&·차집합-·대칭차집합^
- 얕은 복사: b = a는 같은 객체 / a.copy()·a[:] 얕은 복사 / deepcopy로 완전 독립
- 리스트 컴프리헨션: [x**2 for x in range(5) if x%2==0]
- 딕셔너리 컴프리헨션: {k: v for k, v in items}
- 집합 컴프리헨션: {x**2 for x in lst} — 중복 자동 제거
- 제너레이터 표현식: (x**2 for x in range(10)) — 메모리 효율
다음 편 예고 8편 — 파일 입출력 (읽기·쓰기·with문)
open() / read·write·append / with문 / CSV·JSON 파일 다루기
🐍
※ 본 포스팅은 Python 3 공식 문서(docs.python.org)의 Built-in Types 레퍼런스를 기반으로 작성된 학습용 콘텐츠입니다. 코드 예시는 Python 3.10 이상 환경에서 테스트되었습니다.