Lv1 · CLI 계산기 · Lv1 · 단위 변환기 · Lv2 · To-Do List · Lv2 · 단어장 퀴즈
메뉴 선택형 사칙연산 계산기. 결과를 누적해 다음 계산에 사용할 수 있고, 종료 시 전체 이력을 출력합니다. 길이/무게/온도를 양방향으로 변환하는 메뉴 CLI. 변환 함수를 카테고리별로 분리하고 메뉴 핸들러로 매핑합니다. 할 일 추가/조회/완료/삭제 + 우선순위·마감일을 갖춘 메모리 기반 할 일 관리. list 의 dict 컬렉션을 다룹니다. 영-한 사전으로 랜덤 퀴즈. 영→한, 한→영, 랜덤 모드와 틀린 문제만 복습하는 모드까지 구현합니다.
이 강의에서 배우는 것
- 1연산자별 함수를 dict 로 매핑한다
- 20 나누기 예외를 처리한다
- 3이전 결과 재사용 옵션을 구현한다
- 4변환 함수를 단위 쌍별로 정의한다
- 5메뉴 → 핸들러 매핑을 dict 로 한다
- 6f-string 으로 깔끔한 결과 출력
- 7할 일을 dict 로 표현하고 list 에 보관한다
- 8list 명령에 --pending, --sort priority 옵션을 단다
- 9번호로 done/del 을 정확히 처리한다
- 10단어장 dict 에서 랜덤 표본을 뽑는다
- 11영→한, 한→영, 랜덤 모드를 구현한다
- 12틀린 문제만 복습 모드로 다시 푼다
Lv1 · CLI 계산기
메뉴 선택형 사칙연산 계산기. 결과를 누적해 다음 계산에 사용할 수 있고, 종료 시 전체 이력을 출력합니다.
프로젝트 개요
- 메뉴: 1.+ 2.- 3.* 4./ 5.이전 결과 사용 6.종료
- 0 나누기 예외 처리 + 친절한 메시지
- 종료 시 전체 이력 한 번에 출력
요구사항
- OPS dict 에 (기호, 함수) 매핑
- history 리스트에 모든 연산 누적
- 직전 결과를 변수에 저장 → '이전결과 사용' 옵션
도전 과제
- ** (제곱), % (나머지) 추가
- 수식 문자열 직접 파싱 (eval 금지)
채점 체크리스트
- 0 나누기 안전
- 이전 결과 재사용
- 이력 출력
Lv1 · 단위 변환기
길이/무게/온도를 양방향으로 변환하는 메뉴 CLI. 변환 함수를 카테고리별로 분리하고 메뉴 핸들러로 매핑합니다.
프로젝트 개요
- 메뉴: 1.길이(cm↔inch) 2.무게(kg↔lb) 3.온도(°C↔°F) 4.종료
- 각 카테고리 안에서 다시 양방향 선택
- 변환 함수는 카테고리별로 별도 정의
요구사항
- cm_to_inch, inch_to_cm 등 6개 함수
- menu_length / menu_weight / menu_temp 핸들러
- handlers dict 로 메뉴 라우팅
도전 과제
- 환율 변환 추가 (외부 API)
- 자유 입력 형태 (5 km to mile)
채점 체크리스트
- 변환 함수 분리
- 메뉴 라우팅
- 양방향 모두 동작
Lv2 · To-Do List
할 일 추가/조회/완료/삭제 + 우선순위·마감일을 갖춘 메모리 기반 할 일 관리. list 의 dict 컬렉션을 다룹니다.
데이터 모델
[{"task": str, "done": bool, "priority": str, "due": str}, ...]명령
- add — 할 일/우선순위/마감일 입력
- list [--pending] [--sort priority]
- done <번호>
- del <번호>
- quit
도전 과제
- 마감 임박 강조
- 카테고리(태그)
채점 체크리스트
- 5개 명령 동작
- 옵션 처리
- 잘못된 번호 안전
Lv2 · 단어장 퀴즈
영-한 사전으로 랜덤 퀴즈. 영→한, 한→영, 랜덤 모드와 틀린 문제만 복습하는 모드까지 구현합니다.
프로젝트 개요
- 단어장 dict (10개 이상)
- 모드 선택: 영→한 / 한→영 / 랜덤
- 10문제 출제 후 점수 + 틀린 단어 + 복습 옵션
요구사항
- random.sample 로 중복 없이 출제
- 즉시 정답/오답 피드백
- 복습 모드: 틀린 문제만 다시
도전 과제
- 단어장 외부 파일 로드
- 정답률 단어별 누적
채점 체크리스트
- 3가지 모드
- 복습 모드
- 점수 정확
💻 예제 (examples)
실제로 실행해 결과를 확인할 수 있는 예제 코드입니다.
"""CLI 계산기 — 메뉴형 + 결과 누적"""
OPS = {
"1": ("+", lambda a, b: a + b),
"2": ("-", lambda a, b: a - b),
"3": ("*", lambda a, b: a * b),
"4": ("/", lambda a, b: a / b if b != 0 else None),
}
def main():
history = []
last = None
while True:
print("\n[메뉴] 1.+ 2.- 3.* 4./ 5.이전결과 사용 6.종료")
choice = input("선택: ").strip()
if choice == "6":
break
if choice not in OPS:
print("잘못된 선택"); continue
try:
if last is not None and input(f"첫 번째 수 (이전 결과 {last}): ").strip() == "":
a = last
else:
a = float(input("첫 번째 수: "))
b = float(input("두 번째 수: "))
except ValueError:
print("숫자만 입력"); continue
symbol, fn = OPS[choice]
result = fn(a, b)
if result is None:
print("0으로 나눌 수 없습니다")
continue
print(f"결과: {a} {symbol} {b} = {result}")
history.append(f"{a} {symbol} {b} = {result}")
last = result
print("\n[연산 이력]")
for h in history:
print(f" {h}")
if __name__ == "__main__":
main()[메뉴] 1.+ 2.- 3.* 4./ 5.이전결과 사용 6.종료
선택: 1
첫 번째 수: 3
두 번째 수: 4
결과: 3.0 + 4.0 = 7.0
선택: 6
[연산 이력]
3.0 + 4.0 = 7.0"""단위 변환기 — 다중 카테고리 + 양방향"""
def cm_to_inch(cm): return cm / 2.54
def inch_to_cm(inch): return inch * 2.54
def kg_to_lb(kg): return kg * 2.2046226218
def lb_to_kg(lb): return lb / 2.2046226218
def c_to_f(c): return c * 9 / 5 + 32
def f_to_c(f): return (f - 32) * 5 / 9
def menu_length():
direction = input("1.cm→inch 2.inch→cm: ").strip()
val = float(input("값: "))
if direction == "1":
print(f"{val} cm = {cm_to_inch(val):.2f} inch")
else:
print(f"{val} inch = {inch_to_cm(val):.2f} cm")
def menu_weight():
direction = input("1.kg→lb 2.lb→kg: ").strip()
val = float(input("값: "))
if direction == "1":
print(f"{val} kg = {kg_to_lb(val):.2f} lb")
else:
print(f"{val} lb = {lb_to_kg(val):.2f} kg")
def menu_temp():
direction = input("1.°C→°F 2.°F→°C: ").strip()
val = float(input("값: "))
if direction == "1":
print(f"{val}°C = {c_to_f(val):.2f}°F")
else:
print(f"{val}°F = {f_to_c(val):.2f}°C")
def main():
handlers = {"1": menu_length, "2": menu_weight, "3": menu_temp}
while True:
choice = input("\n[메뉴] 1.길이 2.무게 3.온도 4.종료: ").strip()
if choice == "4":
break
if choice in handlers:
handlers[choice]()
if __name__ == "__main__":
main()[메뉴] 1.길이 2.무게 3.온도 4.종료: 1
1.cm→inch 2.inch→cm: 1
값: 100
100.0 cm = 39.37 inch"""To-Do List — 우선순위·마감일 지원"""
PRIORITY_ORDER = {"높음": 0, "보통": 1, "낮음": 2}
todos = []
def add():
task = input("할 일: ").strip()
if not task: return
p = input("우선순위 (높음/보통/낮음, 기본 보통): ").strip() or "보통"
if p not in PRIORITY_ORDER:
p = "보통"
due = input("마감일 (YYYY-MM-DD, 없으면 엔터): ").strip()
todos.append({"task": task, "done": False, "priority": p, "due": due})
print("추가됨")
def show(args=""):
items = list(enumerate(todos, 1))
if "--pending" in args:
items = [(i, t) for i, t in items if not t["done"]]
if "--sort priority" in args:
items.sort(key=lambda x: PRIORITY_ORDER[x[1]["priority"]])
if not items:
print("(비어있음)"); return
for i, t in items:
mark = "[x]" if t["done"] else "[ ]"
due = f"~{t['due']}" if t["due"] else ""
print(f"{i}. {mark}[{t['priority']}] {t['task']} {due}".rstrip())
def main():
while True:
raw = input("\n> ").strip()
if not raw: continue
parts = raw.split(maxsplit=1)
cmd = parts[0]
arg = parts[1] if len(parts) > 1 else ""
if cmd == "quit": break
elif cmd == "add": add()
elif cmd == "list": show(arg)
elif cmd == "done":
try:
idx = int(arg) - 1
if 0 <= idx < len(todos):
todos[idx]["done"] = True
print("완료")
else:
print("번호 없음")
except ValueError:
print("번호를 입력하세요")
elif cmd == "del":
try:
idx = int(arg) - 1
if 0 <= idx < len(todos):
del todos[idx]
print("삭제")
except ValueError:
print("번호를 입력하세요")
else:
print("알 수 없는 명령")
if __name__ == "__main__":
main()> add
할 일: 우유 사기
우선순위: 높음
마감일: 2026-05-12
추가됨
> list
1. [ ][높음] 우유 사기 ~2026-05-12
> done 1
완료"""단어장 퀴즈 — 양방향 + 복습 모드"""
import random
WORDS = {
"apple": "사과", "book": "책", "table": "탁자", "door": "문",
"water": "물", "fire": "불", "tree": "나무", "sky": "하늘",
"love": "사랑", "time": "시간", "house": "집", "car": "자동차",
}
def quiz(pairs, mode):
score = 0
wrong = []
for i, (en, ko) in enumerate(pairs, 1):
if mode == "en2ko":
q, a = en, ko
elif mode == "ko2en":
q, a = ko, en
else: # random
if random.random() < 0.5:
q, a = en, ko
else:
q, a = ko, en
ans = input(f"[{i}/{len(pairs)}] {q}? ").strip()
if ans == a:
print("✓ 정답")
score += 1
else:
print(f"✗ 오답 (정답: {a})")
wrong.append((q, a))
return score, wrong
def main():
print("[모드] 1.영→한 2.한→영 3.랜덤")
mode_map = {"1": "en2ko", "2": "ko2en", "3": "random"}
mode = mode_map.get(input("선택: ").strip(), "en2ko")
pairs = random.sample(list(WORDS.items()), min(10, len(WORDS)))
score, wrong = quiz(pairs, mode)
print(f"\n총점: {score} / {len(pairs)}")
if wrong and input("\n틀린 문제만 복습? (y/n): ").strip().lower() == "y":
score2, _ = quiz(wrong, mode)
print(f"복습 점수: {score2} / {len(wrong)}")
if __name__ == "__main__":
main()[모드] 1.영→한 2.한→영 3.랜덤
선택: 1
[1/10] apple? 사과
✓ 정답
...
총점: 8 / 10
틀린 문제만 복습? (y/n): y
[1/2] water? 물
✓ 정답
복습 점수: 2 / 2📝 과제 (exercises)
직접 풀어보고, 막힐 때 정답을 펼쳐 비교해보세요.
프로젝트 구현
목표: 위 사양대로 직접 작성한다.
- OPS dict + 람다
- 0 나누기 처리
- 이력 출력
lambda a, b: a / b if b != 0 else None
결과: 3.0 + 4.0 = 7.0- · 메뉴 동작
- · 예외 안전
▶정답 코드 펼치기 / 접기
# 위 solution.py 와 동일(예제 참고)프로젝트 구현
목표: 위 사양대로 직접 작성한다.
- 6개 변환 함수
- 3개 메뉴 핸들러
- handlers dict 라우팅
f-string 의 :.2f
100.0 cm = 39.37 inch- · 함수 분리
- · 메뉴 동작
▶정답 코드 펼치기 / 접기
# 위 solution.py 와 동일(예제 참고)프로젝트 구현
목표: 위 사양대로 직접 작성한다.
- dict 리스트
- list/add/done/del/quit
- 옵션 처리
enumerate(todos, 1) 로 번호 매기기
1. [x][높음] 우유 사기- · 5개 명령
- · 옵션 동작
▶정답 코드 펼치기 / 접기
# 위 solution.py 와 동일(예제 참고)프로젝트 구현
목표: 위 사양대로 직접 작성한다.
- WORDS dict
- quiz 함수
- 복습 모드
random.sample(list(WORDS.items()), 10)
총점: 8 / 10- · 3가지 모드
- · 복습
▶정답 코드 펼치기 / 접기
# 위 solution.py 와 동일(예제 참고)댓글 0
아직 댓글이 없습니다. 첫 댓글을 남겨 주세요.
댓글은 회원만 쓸 수 있습니다.
광고·욕설·비방·개인정보·불법 내용이 담긴 댓글은 숨기거나 지웁니다. 댓글은 닉네임과 함께 공개됩니다. 개인정보처리방침