
왜 마지막 장은 프로젝트일까
파이썬 문법을 하나씩 배우는 일은 악기를 배울 때 음계부터 익히는 과정과 비슷합니다. 그런데 음계만 외우고 끝내면 음악이 되지 않듯이, 변수와 반복문과 함수만 따로 알고 있어도 아직 프로그램을 만들 수 있다고 느끼기 어렵습니다. 그래서 마지막에는 꼭 작은 프로젝트가 필요합니다. 직접 무언가를 만들어 보면, 흩어져 있던 문법이 한 번에 연결되기 시작합니다. 실제로 많은 입문 자료가 "파이썬은 만들어 보면서 익힐 때 가장 잘 남는다"는 점을 공통으로 강조합니다.12
이번 장의 목표는 거창한 서비스를 만드는 것이 아닙니다. 대신 아주 작지만 끝까지 돌아가는 프로그램을 만들어 보며, 지금까지 배운 내용이 실제 문제 해결에 어떻게 쓰이는지 확인하는 데 있습니다. 한마디로 말하면, "아, 그래서 이걸 배웠구나!" 하고 고개가 끄덕여지는 장입니다.
지금까지 배운 문법은 프로젝트에서 어떻게 만나나
지금까지 배운 내용은 프로젝트 안에서 따로 놀지 않습니다. 서로 손을 잡고 함께 움직입니다.
변수는 데이터를 기억하고, 조건문은 상황을 판단합니다. 반복문은 같은 작업을 여러 번 처리하고, 리스트와 딕셔너리는 여러 데이터를 모아 관리합니다. 문자열은 사용자 입력이나 파일 내용을 다듬을 때 활약하고, 함수는 코드를 역할별로 나눠 줍니다. 예외 처리는 프로그램이 갑자기 멈추지 않게 지켜 주며, 파일 입출력은 프로그램이 실행이 끝난 뒤에도 데이터를 남길 수 있게 해 줍니다. 마지막으로 클래스는 데이터와 기능을 하나로 묶어, 프로그램이 커져도 덜 헷갈리게 도와줍니다.
예를 들어 "할 일 관리 프로그램"을 만든다고 생각해 봅시다. 사용자가 입력한 할 일은 리스트에 저장하고, 완료 여부는 딕셔너리로 표현할 수 있습니다. 메뉴를 반복해서 보여 주려면 while 문이 필요하고, 잘못된 번호를 입력했을 때는 예외 처리가 필요합니다. 프로그램을 다시 켰을 때도 목록이 남아 있으려면 파일 저장이 필요합니다. 코드가 길어지면 add_task(), show_tasks() 같은 함수로 나누고, 더 깔끔하게 정리하고 싶다면 TaskManager 같은 클래스로 묶을 수 있습니다.
이렇게 보면 프로젝트는 새로운 세계가 아니라, 이미 배운 것들을 한자리에 모아 쓰는 무대입니다.
프로젝트를 작게 시작하는 법
처음부터 너무 큰 것을 만들면 금방 지칩니다. 작은 프로젝트를 끝까지 만드는 경험이 훨씬 중요합니다. 입문용 프로젝트는 "작고, 분명하고, 오늘 당장 한 걸음 나갈 수 있는 것"이 좋습니다.3
프로젝트를 시작할 때는 다음 네 가지를 먼저 정해 보세요.
프로그램이 해결할 문제를 한 문장으로 적습니다.
입력과 출력을 분명히 정합니다.
가장 작은 동작 버전을 먼저 만듭니다.
마지막에 추가할 개선 기능을 한 가지만 정합니다.
예를 들어 "다운로드 폴더 자동 정리기"라면, 문제는 "폴더가 너무 어지럽다"입니다. 입력은 폴더 경로이고, 출력은 확장자별로 정리된 파일입니다. 가장 작은 버전은 이미지와 문서만 나누는 프로그램일 수 있습니다. 그리고 개선 기능으로는 같은 이름 파일이 있을 때 자동 번호 붙이기를 추가하면 됩니다.
이제 실제로 세 가지 미니 프로젝트를 만들어 보겠습니다.
미니 프로젝트 1: 다운로드 폴더 자동 정리기
첫 번째 프로젝트는 자동화 프로그램입니다. 자동화란 사람이 반복해서 하던 일을 프로그램이 대신하게 만드는 것입니다. 파일 이름 바꾸기, 폴더 정리, 이메일 보내기, 데이터 모으기 같은 작업은 파이썬 자동화의 대표적인 예입니다.24
다운로드 폴더를 열어 보면 종종 이런 풍경이 펼쳐집니다. PDF는 PDF끼리 있지 않고, 사진은 문서 사이에 끼어 있고, 동영상은 외롭게 구석에 있습니다. 이럴 때 파일 확장자를 보고 자동으로 폴더를 나누면 꽤 시원합니다.
먼저 꼭 기억할 점
이 프로젝트는 실제 파일을 이동합니다. 그래서 처음에는 중요한 폴더에서 바로 실행하지 말고, 연습용 폴더를 하나 만들어 테스트하는 것을 추천합니다. 자동화 프로그램은 편리하지만, 처음에는 조심스럽게 다루는 편이 좋습니다.
어떻게 동작할까
프로그램은 다음 순서로 움직입니다.
먼저 사용자가 정리할 폴더 경로를 입력합니다. 그다음 폴더 안의 파일들을 하나씩 확인합니다. 파일의 확장자가 .png, .jpg, .pdf 같은 무엇인지 확인한 뒤, 규칙에 따라 images, documents, videos 같은 하위 폴더로 옮깁니다. 만약 같은 이름의 파일이 이미 있으면 번호를 붙여 이름이 겹치지 않게 만듭니다.
코드
from pathlib import Path
import shutil
TARGETS = {
".png": "images",
".jpg": "images",
".jpeg": "images",
".gif": "images",
".pdf": "documents",
".txt": "documents",
".docx": "documents",
".mp4": "videos",
".mov": "videos"
}
def organize_folder(folder_path):
folder = Path(folder_path)
if not folder.exists() or not folder.is_dir():
print("올바른 폴더 경로가 아닙니다.")
return
moved_count = 0
for item in folder.iterdir():
if item.is_file():
extension = item.suffix.lower()
target_name = TARGETS.get(extension, "others")
target_folder = folder / target_name
target_folder.mkdir(exist_ok=True)
new_path = target_folder / item.name
number = 1
while new_path.exists():
new_path = target_folder / f"{item.stem}_{number}{item.suffix}"
number += 1
shutil.move(str(item), str(new_path))
moved_count += 1
print(f"정리가 끝났습니다. {moved_count}개의 파일을 이동했습니다.")
path = input("정리할 폴더 경로를 입력하세요: ").strip()
organize_folder(path)여기서 어떤 문법이 쓰였을까
이 짧은 프로그램 안에도 우리가 배운 내용이 꽤 많이 들어 있습니다.
TARGETS딕셔너리는 확장자와 폴더 이름을 연결합니다.for문은 폴더 안 파일을 하나씩 검사합니다.if문은 파일인지, 어떤 확장자인지 판단합니다.함수
organize_folder()는 전체 작업을 한 덩어리로 묶어 줍니다.Path와shutil모듈은 파일과 폴더를 다루는 일을 쉽게 만들어 줍니다.
이 프로젝트의 좋은 점은 즉시 쓸모가 있다는 것입니다. 내가 만든 프로그램이 내 컴퓨터를 직접 정리해 주니, 갑자기 파이썬이 아주 현실적인 도구처럼 느껴집니다.
이렇게 확장해 보자
여기서 한 단계 더 나가고 싶다면 다음 기능을 붙여 보세요.
오늘 날짜를 기준으로 하위 폴더를 다시 나누기
특정 확장자는 삭제 후보 목록에 따로 모으기
이동한 파일 목록을
log.txt에 기록하기
이런 확장은 단순히 기능 추가가 아닙니다. 실제로는 파일 입출력, 문자열 처리, 날짜 다루기 같은 주제를 자연스럽게 복습하는 일입니다.
미니 프로젝트 2: CSV 가계부 요약기
두 번째 프로젝트는 데이터 처리 프로그램입니다. 데이터 처리란 흩어져 있는 정보를 읽어서, 사람이 이해하기 쉬운 결과로 바꾸는 작업입니다. 파이썬은 CSV, JSON, API 응답처럼 구조가 있는 데이터를 다루기에 특히 편한 언어입니다.2
이번에는 간단한 가계부 파일을 읽어서 카테고리별 지출 합계를 계산해 보겠습니다.
먼저 이런 CSV 파일이 있다고 가정해 보겠습니다.
date,category,amount
2026-03-01,식비,8500
2026-03-01,교통,1400
2026-03-02,식비,12000
2026-03-03,문화,15000
2026-03-03,교통,1400이 파일을 읽어서 "식비 얼마, 교통 얼마, 문화 얼마"를 자동으로 계산하면 됩니다.
코드
import csv
def read_expenses(filename):
totals = {}
total_amount = 0
try:
with open(filename, "r", encoding="utf-8-sig") as file:
reader = csv.DictReader(file)
for row in reader:
try:
category = row["category"].strip()
amount = int(row["amount"])
except (KeyError, ValueError):
print("잘못된 데이터를 건너뜁니다:", row)
continue
totals[category] = totals.get(category, 0) + amount
total_amount += amount
except FileNotFoundError:
print("CSV 파일을 찾을 수 없습니다.")
return {}, 0
return totals, total_amount
def print_report(totals, total_amount):
print("n[지출 요약]")
if not totals:
print("표시할 지출 데이터가 없습니다.")
return
for category, amount in sorted(totals.items(), key=lambda x: x[1], reverse=True):
ratio = amount / total_amount * 100 if total_amount else 0
print(f"{category}: {amount:,}원 ({ratio:.1f}%)")
print(f"총지출: {total_amount:,}원")
filename = input("CSV 파일 이름을 입력하세요: ").strip()
category_totals, grand_total = read_expenses(filename)
print_report(category_totals, grand_total)이 프로젝트에서 배우는 핵심
이 프로그램의 핵심은 "파일 속 글자"를 "의미 있는 정보"로 바꾸는 과정입니다.
csv.DictReader()는 각 줄을 딕셔너리처럼 읽게 해 줍니다. 그래서 row["category"]처럼 키 이름으로 값에 접근할 수 있습니다. 카테고리별 합계를 구할 때는 딕셔너리에 누적하고, 정렬할 때는 sorted()를 씁니다. 잘못된 금액이 들어 있어도 try-except가 있으니 프로그램이 통째로 멈추지 않습니다. 파일 이름을 잘못 입력했을 때도 이제는 친절하게 안내할 수 있습니다.
이 프로젝트를 해 보면 "데이터 처리"가 갑자기 어렵고 멀게 느껴지지 않습니다. 사실 데이터 처리의 시작은 복잡한 인공지능이 아니라, 이런 작은 합계 계산에서 출발하는 경우가 많습니다.
이렇게 바꿔 보면 더 재밌다
가계부 대신 다른 주제로 바꿔도 됩니다. 예를 들어 시험 점수 분석기, 매출 요약기, 독서 기록 분석기처럼 바꿀 수 있습니다. 입력 파일 형식만 조금 다를 뿐, 구조는 거의 비슷합니다.
즉, 한 번 만든 프로그램은 한 번만 쓰고 끝나는 것이 아니라, 모양을 바꿔 여러 문제에 다시 사용할 수 있습니다. 이때 진짜 실력이 붙습니다.
미니 프로젝트 3: 저장되는 할 일 관리 프로그램
세 번째 프로젝트는 관리 프로그램입니다. 이 프로젝트는 지금까지 배운 내용을 가장 넓게 연결해 줍니다. 사용자 입력을 받고, 반복 메뉴를 돌리고, 데이터를 리스트와 딕셔너리로 저장하고, 파일로 남기고, 클래스로 구조까지 정리할 수 있기 때문입니다.
이번에는 프로그램을 껐다 켜도 할 일이 남아 있는 버전을 만들어 보겠습니다. 저장 형식은 JSON을 사용하겠습니다. JSON은 딕셔너리와 리스트 구조를 파일로 저장하기에 아주 잘 맞는 형식입니다.
코드
import json
class TaskManager:
def __init__(self, filename="tasks.json"):
self.filename = filename
self.tasks = []
self.load_tasks()
def load_tasks(self):
try:
with open(self.filename, "r", encoding="utf-8") as file:
self.tasks = json.load(file)
except FileNotFoundError:
self.tasks = []
except json.JSONDecodeError:
print("저장 파일이 손상되어 새 목록으로 시작합니다.")
self.tasks = []
def save_tasks(self):
with open(self.filename, "w", encoding="utf-8") as file:
json.dump(self.tasks, file, ensure_ascii=False, indent=2)
def add_task(self, text):
self.tasks.append({"text": text, "done": False})
self.save_tasks()
print("할 일이 추가되었습니다.")
def show_tasks(self):
if not self.tasks:
print("등록된 할 일이 없습니다.")
return
for i, task in enumerate(self.tasks, start=1):
status = "완료" if task["done"] else "진행 중"
print(f"{i}. {task['text']} [{status}]")
def complete_task(self, index):
if 0 <= index < len(self.tasks):
self.tasks[index]["done"] = True
self.save_tasks()
print("할 일을 완료 처리했습니다.")
else:
print("번호를 다시 확인하세요.")
def main():
manager = TaskManager()
while True:
print("n1. 목록 보기")
print("2. 할 일 추가")
print("3. 완료 처리")
print("4. 종료")
choice = input("메뉴를 선택하세요: ").strip()
if choice == "1":
manager.show_tasks()
elif choice == "2":
text = input("할 일을 입력하세요: ").strip()
if text:
manager.add_task(text)
else:
print("빈 내용은 저장할 수 없습니다.")
elif choice == "3":
try:
number = int(input("완료할 번호를 입력하세요: "))
manager.complete_task(number - 1)
except ValueError:
print("숫자를 입력해야 합니다.")
elif choice == "4":
print("프로그램을 종료합니다.")
break
else:
print("올바른 메뉴 번호를 선택하세요.")
main()왜 이 프로젝트가 특히 좋은가
이 프로젝트는 초보자가 한 단계 성장하기에 아주 좋은 형태입니다. 이유는 간단합니다. 기능이 작고 분명한데, 실전 프로그램의 요소는 거의 다 들어 있기 때문입니다.
우선 메뉴를 계속 보여 주려면 반복문이 필요합니다. 메뉴 선택에 따라 다른 작업을 하려면 조건문이 필요합니다. 할 일을 저장하려면 리스트와 딕셔너리가 필요합니다. 숫자가 아닌 값을 번호 칸에 넣는 실수를 막으려면 예외 처리가 필요합니다. 그리고 프로그램을 껐다 켜도 내용이 남으려면 파일 저장이 필요합니다.
여기에 TaskManager 클래스를 도입하면 데이터와 기능을 한 묶음으로 관리할 수 있습니다. 바로 이 지점에서 클래스가 왜 필요한지가 보입니다. 클래스는 어려운 문법을 뽐내기 위한 장식이 아니라, 프로그램이 커질수록 덜 꼬이게 만드는 정리 상자입니다.
다음 단계는 어떻게 확장할까
이 프로그램은 조금만 손보면 꽤 그럴듯한 개인 앱이 됩니다. 예를 들어 마감일 추가, 삭제 기능, 완료 항목만 보기, 우선순위 정렬 같은 기능을 넣을 수 있습니다. GUI로 바꾸면 작은 데스크톱 앱처럼 보이기까지 합니다.
그리고 여기서 중요한 사실 하나가 보입니다. 처음에는 콘솔 프로그램이었지만, 구조를 잘 잡아 두면 나중에 웹 앱이나 GUI 앱으로 옮기기 쉬워집니다. 즉, 작은 콘솔 프로젝트는 장난감이 아니라 훌륭한 설계 연습입니다.
보너스 도전: 게임으로 실력을 굳히기
만약 실용적인 도구보다 재미있는 쪽이 더 끌린다면, 작은 게임도 아주 좋은 프로젝트입니다. 게임은 루프, 조건문, 함수, 상태 관리, 사용자 입력을 신나게 연습하게 해 줍니다. 특히 2D 입문용으로는 Pygame이 많이 쓰이며, 게임을 만들면서 프로그래밍의 핵심 감각을 키울 수 있습니다.5
처음 도전하기 좋은 게임 아이디어는 다음과 같습니다.
숫자 맞히기 게임: 난이도 선택, 시도 횟수 기록, 최고 기록 저장 추가
퀴즈 게임: 문제를 딕셔너리로 저장하고 점수 계산 기능 넣기
피하기 게임: Pygame으로 플레이어 이동, 충돌 판정, 점수 시스템 만들기
게임 프로젝트를 할 때는 욕심을 조금만 줄이는 것이 좋습니다. 캐릭터 20개, 맵 10개, 보스전 3단계를 넣으려는 순간, 프로젝트는 게임보다 숙제가 됩니다. 반대로 "사각형 하나 움직이기 → 장애물 하나 추가 → 충돌하면 게임 오버"처럼 작게 쪼개면, 오히려 더 빨리 완성하고 더 많이 배웁니다.3
실전 프로젝트를 끝까지 만드는 습관
프로젝트를 시작하는 사람은 많지만, 끝내는 사람은 생각보다 적습니다. 완성 경험이 중요한 이유는, 끝까지 가 봐야 비로소 프로그램의 전체 흐름이 보이기 때문입니다.
다음 습관을 꼭 기억해 두세요.
먼저 돌아가는 최소 버전을 만듭니다.
예쁘게 만들기보다 정확하게 만들기를 먼저 합니다.
오류 메시지를 무서워하지 말고 힌트로 읽습니다.
저장 기능이나 로그 기능처럼 작은 실전 요소를 꼭 넣어 봅니다.
완성한 뒤에는 기능 하나만 더 추가해 봅니다.
이 다섯 가지만 지켜도 프로젝트 경험이 완전히 달라집니다. 프로그램이 한 번 돌아가면, 그다음 개선은 놀랍게도 훨씬 쉬워집니다.
마치며
이제 여러분은 파이썬 문법을 "아는 상태"를 넘어, 파이썬으로 "무언가를 만들 수 있는 상태"에 들어섰습니다. 이 차이는 꽤 큽니다. 문법을 외우는 사람은 많지만, 문제를 보고 스스로 프로그램을 떠올리는 사람은 점점 적어집니다. 그리고 바로 그 차이가 실력을 만듭니다.
처음 프로젝트를 만들 때는 코드가 투박해 보여도 괜찮습니다. 메뉴가 조금 단순해도 괜찮고, 출력이 조금 밋밋해도 괜찮습니다. 중요한 것은 내가 직접 생각하고, 쪼개고, 만들고, 고쳐서 끝까지 실행해 봤다는 사실입니다.
파이썬 공부의 진짜 재미는 여기서부터 시작됩니다. 이제는 책 속 예제를 따라 치는 단계를 넘어, 내 생활의 불편함을 직접 해결하고, 내가 궁금한 데이터를 직접 읽고, 내가 상상한 작은 프로그램을 직접 만들 수 있습니다.
그리고 그 첫걸음으로는, 지금 이 장의 세 프로젝트면 충분합니다. 하나를 골라 오늘 바로 만들어 보세요. 파이썬은 손으로 움직일 때 가장 빨리 늘어납니다.
참고
125 Python Projects for Beginners – Easy Ideas to Get Started Coding Python
2Python Projects: 80+ Ideas for Beginners to Advanced
3Steps to Build Your First Python Game
4GitHub - Yahya-py/Python-Automation---26-Real-World-Projects
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.