🎉 Phase 2 완료 프로젝트! 지금까지 배운 딕셔너리, 컴프리헨션, 문자열 처리를 모두 활용해서 실용적인 프로그램을 만들어봅시다. 함수 없이도 충분히 강력한 프로그램을 만들 수 있어요!
🎯 오늘의 학습 목표
- 딕셔너리로 데이터 관리하기 - CRUD 연산 완벽 이해
- 메뉴 시스템 구현하기 - 사용자 인터페이스 설계
- 입력 검증과 예외 처리 - 안정적인 프로그램 만들기
- 컴프리헨션 활용하기 - 데이터 필터링과 변환
- 통계 기능 구현하기 - 집계 함수 활용
- Phase 2 개념 종합 정리 - 배운 내용 실전 적용
📚 사전 지식
이 프로젝트는 Phase 2에서 배운 모든 개념을 활용합니다:
🎯 학습 목표 1: 딕셔너리로 데이터 관리하기
📌 CRUD 연산이란?
CRUD는 데이터 관리의 4가지 기본 연산입니다:
| 연산 | 영어 | 한글 | 딕셔너리 예시 |
| Create | Create | 생성 | scores["철수"] = 85 |
| Read | Read | 조회 | scores["철수"] |
| Update | Update | 수정 | scores["철수"] = 90 |
| Delete | Delete | 삭제 | del scores["철수"] |
💡 딕셔너리가 최적인 이유
1
2
3
4
5
6
7
8
9
10
11
12
13
| # ❌ 리스트로 관리하면?
names = ["철수", "영희", "민수"]
scores = [85, 90, 78]
# 철수의 점수 찾기 - 번거로움!
index = names.index("철수")
score = scores[index]
# ✅ 딕셔너리로 관리하면?
scores = {"철수": 85, "영희": 90, "민수": 78}
# 철수의 점수 찾기 - 간단!
score = scores["철수"]
|
딕셔너리의 장점:
- 이름(키)로 바로 점수(값) 접근
- 데이터 추가/수정/삭제가 직관적
- 코드 가독성 향상
🔍 실전 예제: 기본 CRUD
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| # 학생 점수 딕셔너리
scores = {}
# 1️⃣ Create - 학생 추가
scores["철수"] = 85
scores["영희"] = 90
scores["민수"] = 78
print(scores)
# 출력: {'철수': 85, '영희': 90, '민수': 78}
# 2️⃣ Read - 점수 조회
print(f"철수의 점수: {scores['철수']}")
# 출력: 철수의 점수: 85
# 안전한 조회 (학생이 없을 수도 있음)
print(f"지영의 점수: {scores.get('지영', '등록되지 않음')}")
# 출력: 지영의 점수: 등록되지 않음
# 3️⃣ Update - 점수 수정
scores["철수"] = 92
print(f"철수의 새 점수: {scores['철수']}")
# 출력: 철수의 새 점수: 92
# 4️⃣ Delete - 학생 삭제
del scores["민수"]
print(scores)
# 출력: {'철수': 92, '영희': 90}
|
⚠️ 주의사항
1
2
3
4
5
6
7
8
9
10
11
12
| # ❌ 존재하지 않는 키 접근 - KeyError 발생!
# print(scores["없는학생"]) # KeyError!
# ✅ 안전한 방법 1: get() 사용
score = scores.get("없는학생", 0)
print(score) # 0
# ✅ 안전한 방법 2: in 연산자로 확인
if "없는학생" in scores:
print(scores["없는학생"])
else:
print("학생이 등록되어 있지 않습니다.")
|
🎯 학습 목표 2: 메뉴 시스템 구현하기
📌 사용자 인터페이스 설계
좋은 프로그램은 사용자가 쉽게 조작할 수 있어야 합니다. 메뉴 시스템을 만들어봅시다!
💡 기본 메뉴 구조
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 메뉴 출력
print("\n" + "="*40)
print(" 학생 점수 관리 프로그램")
print("="*40)
print("1. 학생 추가")
print("2. 점수 조회")
print("3. 점수 수정")
print("4. 학생 삭제")
print("5. 전체 목록 보기")
print("6. 통계 보기")
print("0. 종료")
print("="*40)
choice = input("메뉴를 선택하세요: ").strip()
|
🔍 실전 예제: 메뉴 시스템
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
| scores = {}
# 무한 반복 (while True는 Phase 3에서 배울 예정)
running = True
while running:
# 메뉴 출력
print("\n" + "="*40)
print(" 학생 점수 관리 프로그램")
print("="*40)
print("1. 학생 추가")
print("2. 점수 조회")
print("0. 종료")
print("="*40)
choice = input("메뉴를 선택하세요: ").strip()
# 메뉴 선택 처리
if choice == "1":
# 학생 추가
name = input("학생 이름: ").strip()
# 이미 존재하는 학생인지 확인
if name in scores:
print(f"⚠️ '{name}'은(는) 이미 등록되어 있습니다.")
else:
score_input = input("점수 (0-100): ").strip()
# 점수 검증
if score_input.isdigit():
score = int(score_input)
if 0 <= score <= 100:
scores[name] = score
print(f"✅ '{name}' 학생이 추가되었습니다. (점수: {score})")
else:
print("❌ 점수는 0-100 사이여야 합니다.")
else:
print("❌ 올바른 숫자를 입력하세요.")
elif choice == "2":
# 점수 조회
name = input("조회할 학생 이름: ").strip()
if name in scores:
print(f"📊 {name}의 점수: {scores[name]}점")
else:
print(f"❌ '{name}' 학생을 찾을 수 없습니다.")
elif choice == "0":
# 종료
print("\n👋 프로그램을 종료합니다.")
running = False
else:
print("❌ 올바른 메뉴 번호를 입력하세요.")
|
출력 예시:
1
2
3
4
5
6
7
8
9
10
11
| ========================================
학생 점수 관리 프로그램
========================================
1. 학생 추가
2. 점수 조회
0. 종료
========================================
메뉴를 선택하세요: 1
학생 이름: 철수
점수 (0-100): 85
✅ '철수' 학생이 추가되었습니다. (점수: 85)
|
🎯 학습 목표 3: 입력 검증과 예외 처리
📌 사용자 입력 검증
사용자는 항상 올바른 입력을 하지 않습니다. 프로그램이 망가지지 않도록 검증해야 합니다!
💡 검증 체크리스트
| 검증 항목 | 문제 | 해결 방법 |
| 공백 입력 | name = " " | .strip() 사용 |
| 숫자 형식 | score = "abc" | .isdigit() 확인 |
| 범위 초과 | score = 150 | 0 <= score <= 100 |
| 중복 키 | 같은 이름 | in 연산자 확인 |
| 빈 딕셔너리 | scores = {} | len(scores) 확인 |
🔍 실전 예제: 입력 검증
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| # 1️⃣ 이름 검증
name = input("학생 이름: ").strip()
if not name: # 빈 문자열
print("❌ 이름을 입력하세요.")
elif name.isdigit(): # 숫자만 입력
print("❌ 이름은 문자로 입력하세요.")
else:
print(f"✅ 올바른 이름: {name}")
# 2️⃣ 점수 검증
score_input = input("점수 (0-100): ").strip()
if not score_input:
print("❌ 점수를 입력하세요.")
elif not score_input.isdigit():
print("❌ 숫자를 입력하세요.")
else:
score = int(score_input)
if score < 0 or score > 100:
print("❌ 점수는 0-100 사이여야 합니다.")
else:
print(f"✅ 올바른 점수: {score}")
# 3️⃣ 중복 확인
if name in scores:
print(f"⚠️ '{name}'은(는) 이미 등록되어 있습니다.")
overwrite = input("덮어쓰시겠습니까? (y/n): ").strip().lower()
if overwrite == "y":
scores[name] = score
print("✅ 점수가 수정되었습니다.")
else:
scores[name] = score
print("✅ 학생이 추가되었습니다.")
# 4️⃣ 빈 딕셔너리 확인
if len(scores) == 0:
print("📭 등록된 학생이 없습니다.")
else:
print(f"📊 총 {len(scores)}명의 학생이 등록되어 있습니다.")
|
⚠️ 주의사항
1
2
3
4
5
6
7
8
9
10
| # ❌ 검증 없이 바로 변환 - 위험!
# score = int(input("점수: ")) # "abc" 입력 시 ValueError!
# ✅ 검증 후 변환 - 안전!
score_input = input("점수: ").strip()
if score_input.isdigit():
score = int(score_input)
print(f"점수: {score}")
else:
print("숫자를 입력하세요.")
|
🎯 학습 목표 4: 컴프리헨션 활용하기
📌 데이터 필터링과 변환
리스트 컴프리헨션과 딕셔너리 컴프리헨션을 활용하면 데이터를 쉽게 필터링하고 변환할 수 있습니다!
💡 컴프리헨션 활용 패턴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| scores = {"철수": 85, "영희": 92, "민수": 78, "지영": 95, "현우": 65}
# 1️⃣ 리스트 컴프리헨션: 합격자 이름 목록
# 80점 이상 = 합격
passed = [name for name, score in scores.items() if score >= 80]
print(f"합격자: {passed}")
# 출력: 합격자: ['철수', '영희', '지영']
# 2️⃣ 딕셔너리 컴프리헨션: 우수 학생만 추출
# 90점 이상 = 우수
excellent = {name: score for name, score in scores.items() if score >= 90}
print(f"우수 학생: {excellent}")
# 출력: 우수 학생: {'영희': 92, '지영': 95}
# 3️⃣ 점수 변환: 모든 점수에 보너스 5점
bonus_scores = {name: score + 5 for name, score in scores.items()}
print(f"보너스 적용: {bonus_scores}")
# 출력: 보너스 적용: {'철수': 90, '영희': 97, '민수': 83, '지영': 100, '현우': 70}
# 4️⃣ 등급 변환: 점수를 등급으로
grades = {
name: "A" if score >= 90 else "B" if score >= 80 else "C" if score >= 70 else "F"
for name, score in scores.items()
}
print(f"등급표: {grades}")
# 출력: 등급표: {'철수': 'B', '영희': 'A', '민수': 'C', '지영': 'A', '현우': 'F'}
|
🔍 실전 예제: 점수 필터링
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| scores = {"철수": 85, "영희": 92, "민수": 78, "지영": 95, "현우": 65, "수진": 88}
print("\n📊 점수대별 학생 목록")
print("="*40)
# 90점 이상
excellent = [name for name, score in scores.items() if score >= 90]
print(f"🏆 우수 (90점 이상): {', '.join(excellent) if excellent else '없음'}")
# 80-89점
good = [name for name, score in scores.items() if 80 <= score < 90]
print(f"⭐ 양호 (80-89점): {', '.join(good) if good else '없음'}")
# 70-79점
average = [name for name, score in scores.items() if 70 <= score < 80]
print(f"📝 보통 (70-79점): {', '.join(average) if average else '없음'}")
# 70점 미만
failing = [name for name, score in scores.items() if score < 70]
print(f"⚠️ 미달 (70점 미만): {', '.join(failing) if failing else '없음'}")
|
출력:
1
2
3
4
5
6
| 📊 점수대별 학생 목록
========================================
🏆 우수 (90점 이상): 영희, 지영
⭐ 양호 (80-89점): 철수, 수진
📝 보통 (70-79점): 민수
⚠️ 미달 (70점 미만): 현우
|
🎯 학습 목표 5: 통계 기능 구현하기
📌 집계 함수 활용
Python의 내장 함수 sum(), max(), min(), len()을 활용하면 다양한 통계를 쉽게 계산할 수 있습니다!
💡 기본 통계 계산
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| scores = {"철수": 85, "영희": 92, "민수": 78, "지영": 95, "현우": 65}
# 1️⃣ 학생 수
count = len(scores)
print(f"총 학생 수: {count}명")
# 출력: 총 학생 수: 5명
# 2️⃣ 총점
total = sum(scores.values())
print(f"총점: {total}점")
# 출력: 총점: 415점
# 3️⃣ 평균
average = total / count if count > 0 else 0
print(f"평균: {average:.2f}점")
# 출력: 평균: 83.00점
# 4️⃣ 최고점
highest_score = max(scores.values()) if scores else 0
print(f"최고점: {highest_score}점")
# 출력: 최고점: 95점
# 5️⃣ 최저점
lowest_score = min(scores.values()) if scores else 0
print(f"최저점: {lowest_score}점")
# 출력: 최저점: 65점
# 6️⃣ 최고점 학생 찾기
top_student = max(scores, key=scores.get) if scores else None
print(f"최고점 학생: {top_student} ({scores[top_student]}점)")
# 출력: 최고점 학생: 지영 (95점)
# 7️⃣ 합격자 수 (80점 이상)
passed_count = len([s for s in scores.values() if s >= 80])
print(f"합격자 수 (80점 이상): {passed_count}명")
# 출력: 합격자 수 (80점 이상): 3명
|
🔍 실전 예제: 통계 메뉴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
| scores = {"철수": 85, "영희": 92, "민수": 78, "지영": 95, "현우": 65, "수진": 88}
# 통계 메뉴 선택
print("\n" + "="*40)
print("📊 통계 보기")
print("="*40)
if len(scores) == 0:
print("📭 등록된 학생이 없습니다.")
else:
# 기본 통계
count = len(scores)
total = sum(scores.values())
average = total / count
highest = max(scores.values())
lowest = min(scores.values())
print(f"📚 총 학생 수: {count}명")
print(f"📊 총점: {total}점")
print(f"📈 평균: {average:.2f}점")
print(f"🏆 최고점: {highest}점")
print(f"📉 최저점: {lowest}점")
# 최고점/최저점 학생
top_student = max(scores, key=scores.get)
bottom_student = min(scores, key=scores.get)
print(f"\n🥇 최고점 학생: {top_student} ({scores[top_student]}점)")
print(f"🔻 최저점 학생: {bottom_student} ({scores[bottom_student]}점)")
# 합격/불합격 통계
passed = [name for name, score in scores.items() if score >= 80]
failed = [name for name, score in scores.items() if score < 80]
print(f"\n✅ 합격자 ({len(passed)}명): {', '.join(passed)}")
print(f"❌ 불합격자 ({len(failed)}명): {', '.join(failed)}")
# 등급별 통계
grade_a = len([s for s in scores.values() if s >= 90])
grade_b = len([s for s in scores.values() if 80 <= s < 90])
grade_c = len([s for s in scores.values() if 70 <= s < 80])
grade_f = len([s for s in scores.values() if s < 70])
print(f"\n📊 등급별 분포")
print(f" A등급 (90점 이상): {grade_a}명")
print(f" B등급 (80-89점): {grade_b}명")
print(f" C등급 (70-79점): {grade_c}명")
print(f" F등급 (70점 미만): {grade_f}명")
|
출력:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| ========================================
📊 통계 보기
========================================
📚 총 학생 수: 6명
📊 총점: 503점
📈 평균: 83.83점
🏆 최고점: 95점
📉 최저점: 65점
🥇 최고점 학생: 지영 (95점)
🔻 최저점 학생: 현우 (65점)
✅ 합격자 (4명): 철수, 영희, 지영, 수진
❌ 불합격자 (2명): 민수, 현우
📊 등급별 분포
A등급 (90점 이상): 2명
B등급 (80-89점): 2명
C등급 (70-79점): 1명
F등급 (70점 미만): 1명
|
🎯 학습 목표 6: Phase 2 개념 종합 정리
📌 전체 프로그램 구조
이제 모든 개념을 합쳐서 완전한 프로그램을 만들어봅시다!
💡 프로그램 흐름도
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| 시작
↓
[메뉴 출력]
↓
[사용자 입력]
↓
┌─────────────────┐
│ 1. 학생 추가 │ → 이름/점수 입력 → 검증 → 딕셔너리에 추가
│ 2. 점수 조회 │ → 이름 입력 → 딕셔너리에서 검색 → 출력
│ 3. 점수 수정 │ → 이름/새점수 입력 → 검증 → 딕셔너리 수정
│ 4. 학생 삭제 │ → 이름 입력 → 확인 → 딕셔너리에서 삭제
│ 5. 전체 목록 │ → for문으로 전체 출력
│ 6. 통계 보기 │ → 집계 함수로 통계 계산 → 출력
│ 0. 종료 │ → 프로그램 종료
└─────────────────┘
↓
반복 (메뉴로 돌아가기)
|
🔍 전체 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
| # ========================================
# 학생 점수 관리 프로그램
# Phase 2 프로젝트 - 함수 없이 구현
# ========================================
# 학생 점수를 저장할 딕셔너리
scores = {}
# 프로그램 실행 플래그
running = True
print("="*50)
print(" 🎓 학생 점수 관리 프로그램을 시작합니다!")
print("="*50)
# 메인 루프
while running:
# 메뉴 출력
print("\n" + "="*50)
print(" 📚 학생 점수 관리 프로그램")
print("="*50)
print(" 1. 학생 추가")
print(" 2. 점수 조회")
print(" 3. 점수 수정")
print(" 4. 학생 삭제")
print(" 5. 전체 목록 보기")
print(" 6. 통계 보기")
print(" 0. 종료")
print("="*50)
choice = input("👉 메뉴를 선택하세요: ").strip()
# ============================================
# 1. 학생 추가
# ============================================
if choice == "1":
print("\n" + "-"*50)
print("📝 학생 추가")
print("-"*50)
name = input("학생 이름: ").strip()
# 이름 검증
if not name:
print("❌ 이름을 입력하세요.")
continue
# 중복 확인
if name in scores:
print(f"⚠️ '{name}'은(는) 이미 등록되어 있습니다.")
print(f" 현재 점수: {scores[name]}점")
overwrite = input(" 덮어쓰시겠습니까? (y/n): ").strip().lower()
if overwrite != "y":
print("❌ 취소되었습니다.")
continue
# 점수 입력
score_input = input("점수 (0-100): ").strip()
# 점수 검증
if not score_input:
print("❌ 점수를 입력하세요.")
continue
if not score_input.isdigit():
print("❌ 숫자를 입력하세요.")
continue
score = int(score_input)
if score < 0 or score > 100:
print("❌ 점수는 0-100 사이여야 합니다.")
continue
# 딕셔너리에 추가
scores[name] = score
print(f"✅ '{name}' 학생이 추가되었습니다. (점수: {score}점)")
# ============================================
# 2. 점수 조회
# ============================================
elif choice == "2":
print("\n" + "-"*50)
print("🔍 점수 조회")
print("-"*50)
if len(scores) == 0:
print("📭 등록된 학생이 없습니다.")
continue
name = input("조회할 학생 이름: ").strip()
if not name:
print("❌ 이름을 입력하세요.")
continue
if name in scores:
score = scores[name]
# 등급 계산
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "F"
print(f"\n📊 {name}의 점수 정보")
print(f" 점수: {score}점")
print(f" 등급: {grade}")
# 합격/불합격
if score >= 80:
print(f" 결과: ✅ 합격")
else:
print(f" 결과: ❌ 불합격 (80점 이상 필요)")
else:
print(f"❌ '{name}' 학생을 찾을 수 없습니다.")
# ============================================
# 3. 점수 수정
# ============================================
elif choice == "3":
print("\n" + "-"*50)
print("✏️ 점수 수정")
print("-"*50)
if len(scores) == 0:
print("📭 등록된 학생이 없습니다.")
continue
name = input("수정할 학생 이름: ").strip()
if not name:
print("❌ 이름을 입력하세요.")
continue
if name not in scores:
print(f"❌ '{name}' 학생을 찾을 수 없습니다.")
continue
print(f"현재 점수: {scores[name]}점")
new_score_input = input("새 점수 (0-100): ").strip()
# 점수 검증
if not new_score_input:
print("❌ 점수를 입력하세요.")
continue
if not new_score_input.isdigit():
print("❌ 숫자를 입력하세요.")
continue
new_score = int(new_score_input)
if new_score < 0 or new_score > 100:
print("❌ 점수는 0-100 사이여야 합니다.")
continue
# 딕셔너리 수정
old_score = scores[name]
scores[name] = new_score
print(f"✅ '{name}'의 점수가 수정되었습니다.")
print(f" {old_score}점 → {new_score}점")
# ============================================
# 4. 학생 삭제
# ============================================
elif choice == "4":
print("\n" + "-"*50)
print("🗑️ 학생 삭제")
print("-"*50)
if len(scores) == 0:
print("📭 등록된 학생이 없습니다.")
continue
name = input("삭제할 학생 이름: ").strip()
if not name:
print("❌ 이름을 입력하세요.")
continue
if name not in scores:
print(f"❌ '{name}' 학생을 찾을 수 없습니다.")
continue
print(f"⚠️ '{name}' 학생을 정말 삭제하시겠습니까?")
print(f" 점수: {scores[name]}점")
confirm = input(" 삭제하려면 'y'를 입력하세요: ").strip().lower()
if confirm == "y":
deleted_score = scores[name]
del scores[name]
print(f"✅ '{name}' 학생이 삭제되었습니다. (점수: {deleted_score}점)")
else:
print("❌ 취소되었습니다.")
# ============================================
# 5. 전체 목록 보기
# ============================================
elif choice == "5":
print("\n" + "="*50)
print("📋 전체 학생 목록")
print("="*50)
if len(scores) == 0:
print("📭 등록된 학생이 없습니다.")
continue
print(f"\n총 {len(scores)}명의 학생이 등록되어 있습니다.\n")
# 점수 기준 내림차순 정렬
sorted_scores = sorted(scores.items(), key=lambda x: x[1], reverse=True)
print(f"{'순위':<6} {'이름':<10} {'점수':<8} {'등급':<8} {'상태':<10}")
print("-"*50)
for rank, (name, score) in enumerate(sorted_scores, 1):
# 등급 계산
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "F"
# 합격/불합격
status = "✅ 합격" if score >= 80 else "❌ 불합격"
print(f"{rank:<6} {name:<10} {score:<8} {grade:<8} {status:<10}")
print("-"*50)
# ============================================
# 6. 통계 보기
# ============================================
elif choice == "6":
print("\n" + "="*50)
print("📊 통계 보기")
print("="*50)
if len(scores) == 0:
print("📭 등록된 학생이 없습니다.")
continue
# 기본 통계
count = len(scores)
total = sum(scores.values())
average = total / count
highest = max(scores.values())
lowest = min(scores.values())
print(f"\n📚 기본 통계")
print("-"*50)
print(f"총 학생 수: {count}명")
print(f"총점: {total}점")
print(f"평균: {average:.2f}점")
print(f"최고점: {highest}점")
print(f"최저점: {lowest}점")
# 최고점/최저점 학생
top_student = max(scores, key=scores.get)
bottom_student = min(scores, key=scores.get)
print(f"\n🏆 성적 우수자")
print("-"*50)
print(f"최고점 학생: {top_student} ({scores[top_student]}점)")
print(f"최저점 학생: {bottom_student} ({scores[bottom_student]}점)")
# 합격/불합격 통계
passed = [name for name, score in scores.items() if score >= 80]
failed = [name for name, score in scores.items() if score < 80]
print(f"\n✅ 합격/불합격 통계 (합격 기준: 80점)")
print("-"*50)
print(f"합격자: {len(passed)}명")
if passed:
print(f" → {', '.join(passed)}")
print(f"불합격자: {len(failed)}명")
if failed:
print(f" → {', '.join(failed)}")
# 등급별 통계
grade_a = [name for name, score in scores.items() if score >= 90]
grade_b = [name for name, score in scores.items() if 80 <= score < 90]
grade_c = [name for name, score in scores.items() if 70 <= score < 80]
grade_f = [name for name, score in scores.items() if score < 70]
print(f"\n📊 등급별 분포")
print("-"*50)
print(f"A등급 (90점 이상): {len(grade_a)}명")
if grade_a:
print(f" → {', '.join(grade_a)}")
print(f"B등급 (80-89점): {len(grade_b)}명")
if grade_b:
print(f" → {', '.join(grade_b)}")
print(f"C등급 (70-79점): {len(grade_c)}명")
if grade_c:
print(f" → {', '.join(grade_c)}")
print(f"F등급 (70점 미만): {len(grade_f)}명")
if grade_f:
print(f" → {', '.join(grade_f)}")
# 점수대별 분포
score_90_100 = len([s for s in scores.values() if 90 <= s <= 100])
score_80_89 = len([s for s in scores.values() if 80 <= s < 90])
score_70_79 = len([s for s in scores.values() if 70 <= s < 80])
score_60_69 = len([s for s in scores.values() if 60 <= s < 70])
score_0_59 = len([s for s in scores.values() if 0 <= s < 60])
print(f"\n📈 점수대별 분포")
print("-"*50)
print(f"90-100점: {score_90_100}명 {'█' * score_90_100}")
print(f"80-89점: {score_80_89}명 {'█' * score_80_89}")
print(f"70-79점: {score_70_79}명 {'█' * score_70_79}")
print(f"60-69점: {score_60_69}명 {'█' * score_60_69}")
print(f"0-59점: {score_0_59}명 {'█' * score_0_59}")
# ============================================
# 0. 종료
# ============================================
elif choice == "0":
print("\n" + "="*50)
print(" 👋 프로그램을 종료합니다.")
if len(scores) > 0:
print(f"\n 📊 최종 통계")
print(f" 총 학생 수: {len(scores)}명")
average = sum(scores.values()) / len(scores)
print(f" 전체 평균: {average:.2f}점")
print("\n 감사합니다! 🙏")
print("="*50)
running = False
# ============================================
# 잘못된 입력
# ============================================
else:
print("\n❌ 올바른 메뉴 번호를 입력하세요. (0-6)")
|
💡 실전 팁 & 주의사항
✅ 좋은 습관
- 입력 검증 철저히
1
2
3
4
5
6
| # 항상 .strip()으로 공백 제거
name = input("이름: ").strip()
# 숫자 입력 전 검증
if score_input.isdigit():
score = int(score_input)
|
- 사용자 친화적 메시지
1
2
3
4
5
| # ❌ "에러"
# ✅ "❌ 올바른 숫자를 입력하세요."
# ❌ "성공"
# ✅ "✅ 학생이 추가되었습니다. (점수: 85점)"
|
- 빈 딕셔너리 확인
1
2
3
| if len(scores) == 0:
print("등록된 학생이 없습니다.")
continue
|
- 중요한 작업 전 확인
1
2
3
| confirm = input("정말 삭제하시겠습니까? (y/n): ").strip().lower()
if confirm == "y":
del scores[name]
|
⚠️ 주의사항
- 존재하지 않는 키 접근
1
2
3
4
5
6
7
8
| # ❌ KeyError 발생 가능
# score = scores["없는학생"]
# ✅ 먼저 확인
if name in scores:
score = scores[name]
else:
print("학생을 찾을 수 없습니다.")
|
- 빈 딕셔너리에서 max/min
1
2
3
4
5
6
7
8
| # ❌ ValueError 발생 가능
# highest = max(scores.values())
# ✅ 먼저 확인
if scores:
highest = max(scores.values())
else:
print("학생이 없습니다.")
|
- 0으로 나누기
1
2
3
4
5
| # ❌ ZeroDivisionError 발생 가능
# average = total / count
# ✅ 먼저 확인
average = total / count if count > 0 else 0
|
🧪 연습 문제
문제 1: 기능 추가 - 검색 기능
문제: 점수 범위로 학생을 검색하는 기능을 추가하세요.
- 사용자가 최소 점수와 최대 점수를 입력
- 해당 범위의 학생 목록 출력
💡 힌트
1
2
3
4
5
6
| min_score = int(input("최소 점수: "))
max_score = int(input("최대 점수: "))
# 컴프리헨션 사용
result = [name for name, score in scores.items()
if min_score <= score <= max_score]
|
✅ 정답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| # 메뉴에 "7. 점수 범위 검색" 추가
elif choice == "7":
print("\n" + "-"*50)
print("🔍 점수 범위 검색")
print("-"*50)
if len(scores) == 0:
print("📭 등록된 학생이 없습니다.")
continue
min_input = input("최소 점수 (0-100): ").strip()
max_input = input("최대 점수 (0-100): ").strip()
if not (min_input.isdigit() and max_input.isdigit()):
print("❌ 올바른 숫자를 입력하세요.")
continue
min_score = int(min_input)
max_score = int(max_input)
if not (0 <= min_score <= 100 and 0 <= max_score <= 100):
print("❌ 점수는 0-100 사이여야 합니다.")
continue
if min_score > max_score:
print("❌ 최소 점수가 최대 점수보다 클 수 없습니다.")
continue
# 범위 내 학생 검색
result = {name: score for name, score in scores.items()
if min_score <= score <= max_score}
print(f"\n📊 {min_score}-{max_score}점 범위의 학생")
print("-"*50)
if result:
for name, score in sorted(result.items(), key=lambda x: x[1], reverse=True):
print(f" {name}: {score}점")
print(f"\n총 {len(result)}명")
else:
print("해당 범위의 학생이 없습니다.")
|
문제 2: 기능 개선 - 등급 분포 그래프
문제: 통계 메뉴에서 등급별 분포를 막대 그래프로 시각화하세요.
- A/B/C/F 등급별 학생 수를
█ 문자로 표현 - 예:
A등급: ████ (4명)
💡 힌트
1
2
3
| grade_a_count = len([s for s in scores.values() if s >= 90])
bar = "█" * grade_a_count
print(f"A등급: {bar} ({grade_a_count}명)")
|
✅ 정답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # 통계 메뉴에 추가
print(f"\n📊 등급별 분포 그래프")
print("-"*50)
grade_a = [name for name, score in scores.items() if score >= 90]
grade_b = [name for name, score in scores.items() if 80 <= score < 90]
grade_c = [name for name, score in scores.items() if 70 <= score < 80]
grade_f = [name for name, score in scores.items() if score < 70]
print(f"A등급: {'█' * len(grade_a)} ({len(grade_a)}명)")
print(f"B등급: {'█' * len(grade_b)} ({len(grade_b)}명)")
print(f"C등급: {'█' * len(grade_c)} ({len(grade_c)}명)")
print(f"F등급: {'█' * len(grade_f)} ({len(grade_f)}명)")
# 퍼센트 표시 추가
total_students = len(scores)
if total_students > 0:
print("\n📈 등급별 비율")
print(f"A등급: {len(grade_a)/total_students*100:.1f}%")
print(f"B등급: {len(grade_b)/total_students*100:.1f}%")
print(f"C등급: {len(grade_c)/total_students*100:.1f}%")
print(f"F등급: {len(grade_f)/total_students*100:.1f}%")
|
문제 3: 도전 과제 - 일괄 점수 조정
문제: 모든 학생의 점수에 보너스를 추가하는 기능을 만드세요.
- 사용자가 보너스 점수 입력 (예: +5점)
- 모든 학생 점수에 보너스 추가
- 단, 최대 100점을 넘지 않도록 제한
- 변경 전/후 비교 출력
💡 힌트
1
2
3
4
5
6
| bonus = int(input("보너스 점수: "))
# 딕셔너리 컴프리헨션 활용
# min()으로 100점 제한
new_scores = {name: min(score + bonus, 100)
for name, score in scores.items()}
|
✅ 정답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
| # 메뉴에 "8. 일괄 점수 조정" 추가
elif choice == "8":
print("\n" + "-"*50)
print("⚡ 일괄 점수 조정")
print("-"*50)
if len(scores) == 0:
print("📭 등록된 학생이 없습니다.")
continue
bonus_input = input("보너스 점수 입력 (± 숫자): ").strip()
# 음수도 허용 (점수 감점)
if not (bonus_input.lstrip('-').isdigit()):
print("❌ 올바른 숫자를 입력하세요.")
continue
bonus = int(bonus_input)
if bonus == 0:
print("❌ 0이 아닌 값을 입력하세요.")
continue
print(f"\n모든 학생 점수에 {bonus:+d}점을 적용합니다.")
confirm = input("진행하시겠습니까? (y/n): ").strip().lower()
if confirm != "y":
print("❌ 취소되었습니다.")
continue
print(f"\n📊 점수 조정 결과")
print("-"*50)
print(f"{'이름':<10} {'이전':<8} {'보너스':<8} {'이후':<8} {'변화':<8}")
print("-"*50)
# 새 점수 계산 (0-100 범위 제한)
for name, old_score in scores.items():
new_score = old_score + bonus
# 범위 제한
if new_score > 100:
new_score = 100
elif new_score < 0:
new_score = 0
change = new_score - old_score
print(f"{name:<10} {old_score:<8} {bonus:+d}{' '*4} {new_score:<8} {change:+d}")
# 딕셔너리 업데이트
scores[name] = new_score
print("-"*50)
print("✅ 모든 학생의 점수가 조정되었습니다.")
# 평균 변화
new_average = sum(scores.values()) / len(scores)
print(f"\n📈 새로운 전체 평균: {new_average:.2f}점")
|
📝 오늘 배운 내용 정리
핵심 개념
| 개념 | 설명 | 활용 |
| 딕셔너리 CRUD | Create, Read, Update, Delete | 데이터 관리 |
| 메뉴 시스템 | while + if-elif-else | 사용자 인터페이스 |
| 입력 검증 | .strip(), .isdigit(), in | 안정성 |
| 컴프리헨션 | 리스트/딕셔너리 컴프리헨션 | 데이터 필터링 |
| 집계 함수 | sum(), max(), min(), len() | 통계 계산 |
Phase 2에서 배운 모든 개념 활용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # Day 12: 딕셔너리
scores = {"철수": 85, "영희": 90}
# Day 14: 불린과 논리 연산
if name in scores and scores[name] >= 80:
print("합격")
# Day 15: 타입 변환
score = int(input("점수: "))
# Day 16: f-string
print(f"{name}의 점수: {score}점")
# Day 17: 문자열 메서드
name = input("이름: ").strip().lower()
# Day 18: 리스트 컴프리헨션
passed = [name for name, score in scores.items() if score >= 80]
# Day 19: 딕셔너리 컴프리헨션
high_scores = {name: score for name, score in scores.items() if score >= 90}
|
🎓 Phase 2 완료!
축하합니다! Phase 2의 모든 과정을 완료하셨습니다! 🎉
Phase 2에서 배운 내용:
- ✅ Day 11: 튜플 (tuple)
- ✅ Day 12: 딕셔너리 (dict)
- ✅ Day 13: 세트 (set)
- ✅ Day 14: 불린 (bool)과 논리 연산
- ✅ Day 15: 타입 변환 (Type Casting)
- ✅ Day 16: f-string 포맷팅
- ✅ Day 17: 문자열 메서드
- ✅ Day 18: 리스트 컴프리헨션
- ✅ Day 19: 딕셔너리 컴프리헨션
- ✅ Day 20: Phase 2 프로젝트 (오늘!)
다음 Phase 3에서는:
- Day 21: if문 심화
- Day 22: while문
- Day 23: break/continue
- Day 24: 함수 정의 (def)
- Day 25-29: 함수 심화
- Day 30: Phase 3 프로젝트
🔗 관련 자료
Phase 2 복습
공식 문서
📚 이전 학습
📚 다음 학습
🎉 Phase 2 완료! “늦었다고 생각할 때가 가장 빠른 때”입니다. 지금까지 배운 딕셔너리, 컴프리헨션, 문자열 처리로 실용적인 프로그램을 만들 수 있게 되었습니다. 이제 Phase 3에서 함수와 제어문을 배우면 더욱 강력한 프로그램을 만들 수 있습니다! 💪