Skip to content

6주차 · 자료구조

이번 장에서는 Python의 핵심 4구조를 “처음부터” 익힙니다.

  • list: 순서 있는 가변 컨테이너
  • tuple: 순서 있는 불변 컨테이너
  • dict: key로 찾는 매핑
  • set: 중복 없는 집합
  • [], (), {}, {key: value} 문법 차이를 구분할 수 있습니다.
  • C의 배열/구조체와 Python 자료구조의 차이를 설명할 수 있습니다.

목표는 문법 암기가 아니라, 상황에 맞는 선택 능력입니다.

데이터 구조는 “정리 방식”입니다.

구조 선택이 결과 품질에 미치는 영향
flowchart TB
  A[같은 데이터] --> B[구조를 어떻게 담는가]
  B --> C[찾는 속도]
  B --> D[수정 가능성]
  B --> E[버그 발생률]

예: 학생 이름 100명을 관리할 때

  • 순서 출력이 중요하면 list
  • ID로 즉시 찾으려면 dict
  • 중복 이름 제거가 목적이면 set
구조순서 유지수정 가능권장 사용
list [ ]순회/수정/추가
tuple ( )아니오고정값(좌표, 설정)
dict {k:v}예*key 기반 빠른 조회
set { }인덱스 순서 없음중복 제거, 포함 검사

* Python 3.7+ 삽입 순서 유지

자료구조 문법 quickstart: 기호부터 익히기

Section titled “자료구조 문법 quickstart: 기호부터 익히기”

자료구조는 이름보다 기호 모양을 먼저 눈에 익히는 것이 중요합니다.

구조만드는 문법예시바로 떠올릴 점
list[ ... ][10, 20, 30]순서 있고 수정 가능
tuple( ... )(3, 5)순서 있고 수정 불가
dict{key: value}{"id": "A01", "temp": 23.4}이름으로 찾기
set{ ... } 또는 set(){"ok", "warn"}중복 제거
  1. dict는 콜론 : 이 들어간다. ({"id": "A01"})
  2. set은 값만 적고 콜론이 없다. ({"ok", "warn"})
  3. 빈 중괄호 {}dict 이다.
  4. set은 반드시 set()으로 만든다.
numbers = [1, 2, 3]
point = (3, 5)
sensor = {"id": "A01", "temp": 23.4}
tags = set()
tags.add("ok")
print(numbers[0], point[1], sensor["id"], tags)

list — 인덱스 구조 한눈에 보기

Section titled “list — 인덱스 구조 한눈에 보기”

리스트의 각 원소는 **인덱스(번호)**로 접근합니다. 인덱스는 항상 0부터 시작합니다.

values = [12.4, 11.8, 12.9, 13.1, 12.2]
인덱스01234
원소12.411.812.913.112.2
음수 인덱스-5-4-3-2-1
  • values[0]12.4 (첫 번째)
  • values[-1]12.2 (마지막)
  • values[1:4][11.8, 12.9, 13.1] (인덱스 1 이상, 4 미만)
values = [12.4, 11.8, 12.9, 13.1, 12.2]
values.append(14.0)
values[2] = 12.7
단계연산리스트 상태
초기생성[12.4, 11.8, 12.9, 13.1, 12.2]
1append(14.0)[12.4, 11.8, 12.9, 13.1, 12.2, 14.0]
2values[2] = 12.7[12.4, 11.8, 12.7, 13.1, 12.2, 14.0]
values = [12.4, 11.8, 12.9, 13.1, 12.2]
print(values[0]) # 12.4 첫 값
print(values[-1]) # 12.2 마지막 값
print(values[1:4]) # [11.8, 12.9, 13.1] 0 포함, 4 제외
values[2] = 12.7 # 인덱스 2 수정
values.append(14.0) # 맨 끝에 추가
print(values)
point = (3, 5)
print(point[0])
# point[0] = 7 # TypeError (수정 불가)
  • list는 “변하는 데이터”
  • tuple은 “바뀌면 안 되는 데이터”

key로 값을 꺼내는 구조입니다. 존재하지 않는 key를 []로 바로 조회하면 KeyError가 발생하므로, 조회 전에 key가 있는지 먼저 확인하는 습관을 들이세요.

sensor = {"id": "A01", "temp": 23.4}
print(sensor["temp"]) # key 조회
print(sensor.get("humidity", "N/A")) # 안전 조회 (없으면 기본값 반환)
sensor["status"] = "ok" # 추가/수정

key 존재 확인 패턴:

if "humidity" in sensor:
print(sensor["humidity"])
else:
print("humidity 없음")
tags = {"ok", "warn"}
tags.add("offline")
print("ok" in tags)
print(set(["ok", "ok", "warn"])) # {'ok', 'warn'}
  • set은 중복 제거와 포함 검사에 특화
  • 출력 순서를 기대하면 안 됨 (sorted() 권장)

5) 알고리즘적 사고: 구조 선택 절차

Section titled “5) 알고리즘적 사고: 구조 선택 절차”

문제: “센서 상태를 저장하고, ID로 빠르게 조회하며, 상태 중복을 제거하라”

  1. 원본 레코드 여러 개 → list[dict]
  2. ID 조회 최적화 → dict (ID -> row)
  3. 상태값 중복 제거 → set
  4. 화면 출력 안정화 → sorted(set_result)
구조 조합 패턴
flowchart TB
  A[records<br/>list of dict] --> B[lookup dict by id]
  A --> C[status list]
  C --> D[set 중복 제거]
  D --> E[sorted list 출력]

C와 비교: 배열/struct와 Python 자료구조는 이렇게 다릅니다

Section titled “C와 비교: 배열/struct와 Python 자료구조는 이렇게 다릅니다”
항목CPython기억할 점
순차 데이터배열 int a[3]list / tuplePython은 크기와 타입이 더 유연하다
레코드 데이터structdictPython은 key 문자열로 바로 접근
중복 제거직접 구현setPython은 집합이 기본 제공
수정 가능성선언 방식에 따라 다름list/dict/set 수정 가능, tuple 불가선택이 문법에 드러난다
struct Sensor {
char id[10];
double temp;
};
struct Sensor s = {"A01", 23.4};
printf("%s %.1f\n", s.id, s.temp);

핵심은 배열처럼 순서가 중요하면 list/tuple, 구조체처럼 이름으로 찾고 싶으면 dict, 중복 제거가 필요하면 set 입니다.

  1. 자료형부터 출력: print(type(x), x)
  2. 길이 확인: len(list_or_dict)
  3. key 조회 전 존재 확인: if key in d:
  4. 슬라이싱 결과 직접 출력: print(a[1:4])
  5. 복사 실수 점검: b = a.copy() 사용

Bad

lookup = {"A01": 23.4}
print(lookup["A03"]) # KeyError 발생

Good

# 방법 1: get() 사용
print(lookup.get("A03", "missing"))
# 방법 2: in 으로 먼저 확인
if "A03" in lookup:
print(lookup["A03"])
else:
print("A03 없음")

Bad

a = [1, 2, 3]
b = a
b[0] = 99
print(a) # [99, 2, 3] 원본도 바뀜!
리스트 참조 vs 복사
flowchart LR
  subgraph "b = a (참조 공유)"
    direction TB
    varA1["변수 a"] --> list1["[1, 2, 3]"]
    varB1["변수 b"] --> list1
  end
  subgraph "b = a.copy() (독립 복사)"
    direction TB
    varA2["변수 a"] --> list2["[1, 2, 3]"]
    varB2["변수 b"] --> list3["[1, 2, 3]"]
  end

Good

a = [1, 2, 3]
b = a.copy()
b[0] = 99
print(a) # [1, 2, 3] 원본 유지
예제 1 · 인덱싱, 슬라이싱, 수정 Runs in-browser with Pyodide
Ready
  1. numbers = [12.4, 11.8, 12.9, 13.1, 12.2] — 실수 5개짜리 리스트 생성
  2. numbers[0]12.4, numbers[-1]12.2 — 양수/음수 인덱싱으로 첫/끝 값 조회
  3. numbers[1:4][11.8, 12.9, 13.1] — 인덱스 1 이상 4 미만 구간 추출
  4. numbers[2] = 12.7 — 인덱스 2(세 번째 원소 12.9)를 12.7로 수정
  5. numbers.append(14.0) — 리스트 맨 끝에 새 값 추가
  6. meta = ("sensor-A", "2026-03-01") — 튜플 생성 후 읽기만 수행 (수정 불가)
예제 2 · dict 구성과 set 중복 제거 Runs in-browser with Pyodide
Ready
  1. list[dict] 형태로 레코드 저장
  2. for 루프로 lookup dict를 직접 구성 — lookup[row["id"]] = row
  3. if "A02" in lookup: — key 존재를 먼저 확인한 뒤 [] 조회 (KeyError 방지)
  4. lookup.get("A04", "missing") — 없는 key는 기본값 반환
  5. set(tags) — 중복 제거
  6. sorted() — 출력 안정화
예제 3 · 자료구조 실수와 수정 Runs in-browser with Pyodide
Ready
  1. if "A02" in lookup: — key가 있는지 먼저 확인 (try/except 없이 안전 처리)
  2. lookup.get("A02", -1) — 없는 key에 기본값 반환하는 두 번째 안전 방법
  3. alias = origin — 참조 복사: alias와 origin이 같은 리스트를 가리킴
  4. alias[0] = 99 — alias를 수정했는데 origin도 함께 바뀌는 것을 관찰
  5. origin.copy() — 독립 복사본 생성 → clone 수정이 origin에 영향 없음
실수증상원인수정 방법
tuple을 list처럼 수정TypeError불변 자료형 개념 부족수정 필요 데이터는 list 사용
슬라이싱 끝 인덱스 오해범위가 1칸 어긋남끝 인덱스 제외 규칙 미이해start <= i < end 기억
dict 없는 key 즉시 조회KeyError방어 코드 없음get() 또는 if key in dict
set 출력 순서 기대실행마다 순서가 달라 보임set은 순서형이 아님sorted(set_data)로 표시
b = a를 깊은 복사로 오해원본까지 변경참조 공유a.copy() 또는 list(a)

문제: 점수 리스트의 최고/최저/평균을 구하세요.

실습 문제 1 · list 통계 내기 Runs in-browser with Pyodide
Ready