
파이썬의 기본 개념들을 모두 활용한 학생 성적 관리 시스템을 만들어보겠습니다. 이 프로그램은 학생의 정보와 성적을 입력, 조회, 수정, 삭제할 수 있고, 파일에 저장하고 불러올 수 있는 기능을 제공합니다.
1. 필요한 모듈 임포트 및 전역 변수 선언
import os
import csv
import json
from datetime import datetime
# 변수와 자료형
FILE_PATH = "students.csv" # 문자열 변수
JSON_PATH = "students.json" # JSON 파일 경로
SUBJECTS = ["국어", "영어", "수학", "과학", "사회"] # 리스트 변수
MIN_SCORE = 0 # 정수 변수
MAX_SCORE = 100 # 정수 변수
VERSION = 1.0 # 실수 변수
IS_DEBUG = False # 불리언 변수
이 부분에서는 파일 처리, CSV, JSON 처리 등을 위한 모듈들을 임포트하고, 프로그램에서 사용할 전역 변수들을 다양한 자료형으로 선언하고 있습니다.
2. Student 클래스
class Student:
"""학생 클래스 - 학생 정보와 성적을 관리합니다."""
def __init__(self, student_id, name, grade):
"""생성자 함수"""
self.student_id = student_id # 학번
self.name = name # 이름
self.grade = grade # 학년
self.scores = {} # 과목별 점수를 저장할 딕셔너리
self.created_at = datetime.now() # 생성 시간
self.updated_at = self.created_at # 마지막 수정 시간
Student 클래스는 개별 학생의 정보와 성적을 관리합니다. 생성자 함수(__init__)에서 학생의 기본 정보를 초기화하고, 각 과목별 점수를 저장할 빈 딕셔너리를 생성합니다.
3. 학생 클래스의 메서드
def add_score(self, subject, score):
"""과목 점수 추가 함수"""
# 점수 범위 확인 (조건문)
if score < MIN_SCORE or score > MAX_SCORE:
return False
self.scores[subject] = score
self.updated_at = datetime.now()
return True
def get_average(self):
"""평균 점수 계산 함수"""
if not self.scores:
return 0
total = sum(self.scores.values())
return round(total / len(self.scores), 2)
def get_grade_letter(self):
"""학점 계산 함수"""
avg = self.get_average()
# 조건문을 사용한 학점 부여
if avg >= 90:
return "A"
elif avg >= 80:
return "B"
elif avg >= 70:
return "C"
elif avg >= 60:
return "D"
else:
return "F"
이 메서드들은 학생 객체의 기능을 정의합니다:
- add_score(): 과목과 점수를 입력받아 학생의 성적을 추가하고, 조건문을 통해 점수 범위를 검증합니다.
- get_average(): 학생의 모든 과목 점수의 평균을 계산합니다.
- get_grade_letter(): 평균 점수를 기반으로 학점(A, B, C, D, F)을 부여합니다. 여기서 중첩 조건문이 사용됩니다.
4. StudentManager 클래스
class StudentManager:
"""학생 관리 클래스 - 여러 학생의 정보를 관리합니다."""
def __init__(self):
"""생성자 함수"""
self.students = {} # 학생들을 저장할 딕셔너리 (키: 학번, 값: Student 객체)
StudentManager 클래스는 여러 학생 객체를 관리하기 위한 클래스입니다. 딕셔너리를 사용하여 학번을 키로, Student 객체를 값으로 저장합니다.
5. 학생 관리 클래스의 메서드들
def add_student(self, student_id, name, grade):
"""학생 추가 함수"""
# 이미 존재하는 학번인지 확인
if student_id in self.students:
return False
student = Student(student_id, name, grade)
self.students[student_id] = student
return True
def remove_student(self, student_id):
"""학생 삭제 함수"""
if student_id in self.students:
del self.students[student_id]
return True
return False
def get_student(self, student_id):
"""학생 정보 조회 함수"""
return self.students.get(student_id)
def get_all_students(self):
"""모든 학생 정보 조회 함수"""
return list(self.students.values())
이 메서드들은 학생 관리의 기본 CRUD 기능을 구현합니다:
- add_student(): 새 학생을 추가하고 중복 학번을 검사합니다.
- remove_student(): 지정된 학번의 학생을 삭제합니다.
- get_student(): 특정 학번의 학생 정보를 조회합니다.
- get_all_students(): 모든 학생 정보를 리스트로 반환합니다.
6. 파일 입출력 메서드들
def save_to_csv(self, file_path=FILE_PATH):
"""학생 정보를 CSV 파일로 저장하는 함수"""
try:
with open(file_path, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
# 헤더 작성
header = ["학번", "이름", "학년", "평균", "학점"] + SUBJECTS
writer.writerow(header)
# 학생 정보 작성
for student in self.students.values():
row = [
student.student_id,
student.name,
student.grade,
student.get_average(),
student.get_grade_letter()
]
# 과목별 점수 추가
for subject in SUBJECTS:
row.append(student.scores.get(subject, ""))
writer.writerow(row)
print(f"CSV 파일 저장 완료: {file_path}")
return True
except Exception as e:
print(f"CSV 파일 저장 실패: {e}")
return False
파일 입출력 메서드는 학생 정보를 CSV와 JSON 형식으로 저장하고 불러오는 기능을 제공합니다:
- save_to_csv(): 모든 학생 정보를 CSV 파일로 저장합니다.
- load_from_csv(): CSV 파일에서 학생 정보를 불러옵니다.
- save_to_json(): 모든 학생 정보를 JSON 파일로 저장합니다.
- load_from_json(): JSON 파일에서 학생 정보를 불러옵니다.
7. 사용자 인터페이스 함수들
def print_menu():
"""메뉴 출력 함수"""
print("\n===== 학생 성적 관리 시스템 =====")
print("1. 학생 추가")
print("2. 학생 삭제")
print("3. 학생 정보 조회")
# ... 생략 ...
print("0. 종료")
print("==========================")
def input_student_info():
"""학생 정보 입력 함수"""
student_id = input("학번 입력: ")
name = input("이름 입력: ")
while True:
try:
grade = int(input("학년 입력 (1-6): "))
if 1 <= grade <= 6:
break
else:
print("학년은 1부터 6 사이의 숫자로 입력해주세요.")
except ValueError:
print("숫자를 입력해주세요.")
return student_id, name, grade
사용자 인터페이스 함수들은 메뉴 출력과 사용자 입력을 처리합니다:
- print_menu(): 메인 메뉴를 출력합니다.
- input_student_info(): 학생 정보를 입력받는 함수입니다. 반복문과 예외 처리를 사용합니다.
- input_score(): 성적 정보를 입력받는 함수입니다.
8. 메인 함수
def main():
"""메인 함수"""
manager = StudentManager()
# 샘플 데이터 생성
if IS_DEBUG:
manager.add_student("20230001", "홍길동", 3)
manager.add_score("20230001", "국어", 85)
# ... 생략 ...
while True:
print_menu()
choice = input("메뉴 선택: ")
if choice == "1": # 학생 추가
student_id, name, grade = input_student_info()
if manager.add_student(student_id, name, grade):
print(f"학생 추가 완료: {name} ({student_id})")
else:
print(f"이미 존재하는 학번입니다: {student_id}")
# ... 다른 메뉴 처리 ...
elif choice == "0": # 종료
print("프로그램을 종료합니다.")
break
else:
print("잘못된 메뉴 선택입니다. 다시 선택해주세요.")
메인 함수(main())는 프로그램의 전체 흐름을 제어합니다:
- StudentManager 객체를 생성하여 학생 관리자 인스턴스를 초기화합니다.
- 디버그 모드가 활성화되어 있으면 샘플 데이터를 생성합니다.
- 무한 루프를 통해 사용자가 종료할 때까지 메뉴를 반복해서 표시합니다.
- 사용자 입력에 따라 다양한 기능을 실행합니다:
- 학생 추가/삭제/조회
- 성적 입력
- 파일 저장/불러오기
메인 함수는 반복문(while)과 조건문(if-elif-else)을 사용하여 메뉴 선택에 따른 분기 처리를 수행합니다.
9. 진입점 (Entry Point)
if __name__ == "__main__":
main()
이 코드는 스크립트가 직접 실행될 때만 main() 함수를 호출하고, 다른 모듈에서 임포트될 때는 실행되지 않도록 합니다.
파이썬 주요 개념 적용 사항
㉮ 변수와 자료형
- 문자열: FILE_PATH, JSON_PATH, student.name 등
- 정수: MIN_SCORE, MAX_SCORE, student.grade 등
- 실수: VERSION, student.get_average() 결과값
- 불리언: IS_DEBUG, 함수의 반환값 (True/False)
- 리스트: SUBJECTS
- 딕셔너리: student.scores, manager.students
㉯ 조건문
- 점수 범위 검증: if score < MIN_SCORE or score > MAX_SCORE
- 학점 계산: if avg >= 90: ... elif avg >= 80: ...
- 메뉴 선택 처리: if choice == "1": ... elif choice == "2": ...
㉰ 반복문
- for student in self.students.values(): - 학생 정보 순회
- while True: - 메인 메뉴 무한 반복
- for subject in SUBJECTS: - 과목 리스트 순회
- while True: try: ... except: - 사용자 입력 검증을 위한 반복
㉱ 함수
- 클래스 메서드: add_student(), get_average() 등
- 일반 함수: print_menu(), input_student_info(), main()
- 생성자 함수: __init__()
- 매직 메서드: __str__()
㉲ 파일 입출력
- CSV 파일 처리: save_to_csv(), load_from_csv()
- JSON 파일 처리: save_to_json(), load_from_json()
- 파일 열기/쓰기: with open(file_path, 'w') as f:
㉳ 예외 처리
- try: ... except ValueError: ... - 숫자 입력 검증
- try: ... except Exception as e: ... - 파일 처리 오류 포착
㉴ 클래스와 객체지향 프로그래밍
- Student 클래스: 개별 학생 정보와 성적 관리
- StudentManager 클래스: 여러 학생 객체 관리
- 상속, 캡슐화, 다형성 등의 객체지향 개념 적용
전체코드
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import csv
import json
from datetime import datetime
# 변수와 자료형
FILE_PATH = "students.csv" # 문자열 변수
JSON_PATH = "students.json" # JSON 파일 경로
SUBJECTS = ["국어", "영어", "수학", "과학", "사회"] # 리스트 변수
MIN_SCORE = 0 # 정수 변수
MAX_SCORE = 100 # 정수 변수
VERSION = 1.0 # 실수 변수
IS_DEBUG = False # 불리언 변수
class Student:
"""학생 클래스 - 학생 정보와 성적을 관리합니다."""
def __init__(self, student_id, name, grade):
"""생성자 함수"""
self.student_id = student_id # 학번
self.name = name # 이름
self.grade = grade # 학년
self.scores = {} # 과목별 점수를 저장할 딕셔너리
self.created_at = datetime.now() # 생성 시간
self.updated_at = self.created_at # 마지막 수정 시간
def add_score(self, subject, score):
"""과목 점수 추가 함수"""
# 점수 범위 확인 (조건문)
if score < MIN_SCORE or score > MAX_SCORE:
return False
self.scores[subject] = score
self.updated_at = datetime.now()
return True
def get_average(self):
"""평균 점수 계산 함수"""
if not self.scores:
return 0
total = sum(self.scores.values())
return round(total / len(self.scores), 2)
def get_grade_letter(self):
"""학점 계산 함수"""
avg = self.get_average()
# 조건문을 사용한 학점 부여
if avg >= 90:
return "A"
elif avg >= 80:
return "B"
elif avg >= 70:
return "C"
elif avg >= 60:
return "D"
else:
return "F"
def to_dict(self):
"""학생 정보를 딕셔너리로 변환"""
return {
"student_id": self.student_id,
"name": self.name,
"grade": self.grade,
"scores": self.scores,
"average": self.get_average(),
"grade_letter": self.get_grade_letter(),
"created_at": self.created_at.strftime("%Y-%m-%d %H:%M:%S"),
"updated_at": self.updated_at.strftime("%Y-%m-%d %H:%M:%S")
}
def __str__(self):
"""학생 정보를 문자열로 반환"""
info = f"학번: {self.student_id}, 이름: {self.name}, 학년: {self.grade}\n"
info += f"평균: {self.get_average()}, 학점: {self.get_grade_letter()}\n"
info += "과목별 점수:\n"
# 반복문을 사용하여 과목별 점수 출력
for subject in SUBJECTS:
score = self.scores.get(subject, "미입력")
info += f"- {subject}: {score}\n"
return info
class StudentManager:
"""학생 관리 클래스 - 여러 학생의 정보를 관리합니다."""
def __init__(self):
"""생성자 함수"""
self.students = {} # 학생들을 저장할 딕셔너리 (키: 학번, 값: Student 객체)
def add_student(self, student_id, name, grade):
"""학생 추가 함수"""
# 이미 존재하는 학번인지 확인
if student_id in self.students:
return False
student = Student(student_id, name, grade)
self.students[student_id] = student
return True
def remove_student(self, student_id):
"""학생 삭제 함수"""
if student_id in self.students:
del self.students[student_id]
return True
return False
def get_student(self, student_id):
"""학생 정보 조회 함수"""
return self.students.get(student_id)
def get_all_students(self):
"""모든 학생 정보 조회 함수"""
return list(self.students.values())
def add_score(self, student_id, subject, score):
"""학생 점수 추가 함수"""
student = self.get_student(student_id)
if student:
return student.add_score(subject, score)
return False
def get_top_student(self):
"""최고 평균 점수 학생 조회 함수"""
if not self.students:
return None
top_student = None
max_avg = -1
# 반복문을 사용하여 최고 점수 학생 찾기
for student in self.students.values():
avg = student.get_average()
if avg > max_avg:
max_avg = avg
top_student = student
return top_student
def save_to_csv(self, file_path=FILE_PATH):
"""학생 정보를 CSV 파일로 저장하는 함수"""
try:
with open(file_path, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
# 헤더 작성
header = ["학번", "이름", "학년", "평균", "학점"] + SUBJECTS
writer.writerow(header)
# 학생 정보 작성
for student in self.students.values():
row = [
student.student_id,
student.name,
student.grade,
student.get_average(),
student.get_grade_letter()
]
# 과목별 점수 추가
for subject in SUBJECTS:
row.append(student.scores.get(subject, ""))
writer.writerow(row)
print(f"CSV 파일 저장 완료: {file_path}")
return True
except Exception as e:
print(f"CSV 파일 저장 실패: {e}")
return False
def load_from_csv(self, file_path=FILE_PATH):
"""CSV 파일에서 학생 정보를 불러오는 함수"""
if not os.path.exists(file_path):
print(f"파일이 존재하지 않습니다: {file_path}")
return False
try:
self.students = {} # 기존 데이터 초기화
with open(file_path, 'r', encoding='utf-8') as f:
reader = csv.reader(f)
header = next(reader) # 헤더 읽기
for row in reader:
if len(row) < 5: # 최소 필드 수 확인
continue
student_id = row[0]
name = row[1]
grade = int(row[2])
# 학생 추가
self.add_student(student_id, name, grade)
student = self.get_student(student_id)
# 과목별 점수 추가
for i, subject in enumerate(SUBJECTS):
idx = i + 5 # 학번, 이름, 학년, 평균, 학점 다음부터 과목 점수
if idx < len(row) and row[idx]:
student.add_score(subject, int(row[idx]))
print(f"CSV 파일 불러오기 완료: {file_path}")
return True
except Exception as e:
print(f"CSV 파일 불러오기 실패: {e}")
return False
def save_to_json(self, file_path=JSON_PATH):
"""학생 정보를 JSON 파일로 저장하는 함수"""
try:
data = {
"version": VERSION,
"students": [student.to_dict() for student in self.students.values()]
}
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"JSON 파일 저장 완료: {file_path}")
return True
except Exception as e:
print(f"JSON 파일 저장 실패: {e}")
return False
def load_from_json(self, file_path=JSON_PATH):
"""JSON 파일에서 학생 정보를 불러오는 함수"""
if not os.path.exists(file_path):
print(f"파일이 존재하지 않습니다: {file_path}")
return False
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
# 버전 확인
if "version" in data and data["version"] != VERSION:
print(f"경고: 버전이 다릅니다. 현재: {VERSION}, 파일: {data['version']}")
self.students = {} # 기존 데이터 초기화
if "students" in data:
for student_data in data["students"]:
student_id = student_data["student_id"]
name = student_data["name"]
grade = student_data["grade"]
# 학생 추가
self.add_student(student_id, name, grade)
student = self.get_student(student_id)
# 점수 추가
if "scores" in student_data:
for subject, score in student_data["scores"].items():
student.add_score(subject, score)
print(f"JSON 파일 불러오기 완료: {file_path}")
return True
except Exception as e:
print(f"JSON 파일 불러오기 실패: {e}")
return False
def print_menu():
"""메뉴 출력 함수"""
print("\n===== 학생 성적 관리 시스템 =====")
print("1. 학생 추가")
print("2. 학생 삭제")
print("3. 학생 정보 조회")
print("4. 모든 학생 정보 조회")
print("5. 성적 입력")
print("6. 최고 평균 학생 조회")
print("7. CSV 파일로 저장")
print("8. CSV 파일에서 불러오기")
print("9. JSON 파일로 저장")
print("10. JSON 파일에서 불러오기")
print("0. 종료")
print("==========================")
def input_student_info():
"""학생 정보 입력 함수"""
student_id = input("학번 입력: ")
name = input("이름 입력: ")
while True:
try:
grade = int(input("학년 입력 (1-6): "))
if 1 <= grade <= 6:
break
else:
print("학년은 1부터 6 사이의 숫자로 입력해주세요.")
except ValueError:
print("숫자를 입력해주세요.")
return student_id, name, grade
def input_score():
"""점수 입력 함수"""
student_id = input("학생 학번 입력: ")
# 과목 선택
print("과목 선택:")
for i, subject in enumerate(SUBJECTS, 1):
print(f"{i}. {subject}")
while True:
try:
choice = int(input("과목 번호 선택: "))
if 1 <= choice <= len(SUBJECTS):
subject = SUBJECTS[choice - 1]
break
else:
print(f"1부터 {len(SUBJECTS)} 사이의 숫자를 입력해주세요.")
except ValueError:
print("숫자를 입력해주세요.")
# 점수 입력
while True:
try:
score = int(input(f"{subject} 점수 입력 (0-100): "))
if MIN_SCORE <= score <= MAX_SCORE:
break
else:
print(f"점수는 {MIN_SCORE}부터 {MAX_SCORE} 사이의 숫자로 입력해주세요.")
except ValueError:
print("숫자를 입력해주세요.")
return student_id, subject, score
def main():
"""메인 함수"""
manager = StudentManager()
# 샘플 데이터 생성
if IS_DEBUG:
manager.add_student("20230001", "홍길동", 3)
manager.add_score("20230001", "국어", 85)
manager.add_score("20230001", "영어", 92)
manager.add_score("20230001", "수학", 78)
manager.add_student("20230002", "김철수", 3)
manager.add_score("20230002", "국어", 90)
manager.add_score("20230002", "영어", 85)
manager.add_score("20230002", "수학", 95)
print("샘플 데이터가 생성되었습니다.")
while True:
print_menu()
choice = input("메뉴 선택: ")
if choice == "1": # 학생 추가
student_id, name, grade = input_student_info()
if manager.add_student(student_id, name, grade):
print(f"학생 추가 완료: {name} ({student_id})")
else:
print(f"이미 존재하는 학번입니다: {student_id}")
elif choice == "2": # 학생 삭제
student_id = input("삭제할 학생의 학번 입력: ")
if manager.remove_student(student_id):
print(f"학생 삭제 완료: {student_id}")
else:
print(f"학생이 존재하지 않습니다: {student_id}")
elif choice == "3": # 학생 정보 조회
student_id = input("조회할 학생의 학번 입력: ")
student = manager.get_student(student_id)
if student:
print(student)
else:
print(f"학생이 존재하지 않습니다: {student_id}")
elif choice == "4": # 모든 학생 정보 조회
students = manager.get_all_students()
if students:
print(f"\n총 {len(students)}명의 학생이 있습니다.")
for i, student in enumerate(students, 1):
print(f"\n[{i}] {student}")
else:
print("등록된 학생이 없습니다.")
elif choice == "5": # 성적 입력
student_id, subject, score = input_score()
if manager.add_score(student_id, subject, score):
print(f"성적 입력 완료: {student_id}, {subject}, {score}")
else:
print(f"성적 입력 실패: 학생이 존재하지 않거나 점수가 범위를 벗어났습니다.")
elif choice == "6": # 최고 평균 학생 조회
top_student = manager.get_top_student()
if top_student:
print("\n[최고 평균 학생]")
print(top_student)
else:
print("등록된 학생이 없습니다.")
elif choice == "7": # CSV 파일로 저장
file_path = input(f"저장할 CSV 파일 경로 (기본값: {FILE_PATH}): ") or FILE_PATH
manager.save_to_csv(file_path)
elif choice == "8": # CSV 파일에서 불러오기
file_path = input(f"불러올 CSV 파일 경로 (기본값: {FILE_PATH}): ") or FILE_PATH
manager.load_from_csv(file_path)
elif choice == "9": # JSON 파일로 저장
file_path = input(f"저장할 JSON 파일 경로 (기본값: {JSON_PATH}): ") or JSON_PATH
manager.save_to_json(file_path)
elif choice == "10": # JSON 파일에서 불러오기
file_path = input(f"불러올 JSON 파일 경로 (기본값: {JSON_PATH}): ") or JSON_PATH
manager.load_from_json(file_path)
elif choice == "0": # 종료
print("프로그램을 종료합니다.")
break
else:
print("잘못된 메뉴 선택입니다. 다시 선택해주세요.")
if __name__ == "__main__":
main()
작동방식
프로그램 작동 방식
- 프로그램을 실행하면 메인 메뉴가 표시됩니다.
- 사용자는 메뉴에서 원하는 기능을 선택할 수 있습니다:
- 학생 추가: 학번, 이름, 학년 정보를 입력하여 새 학생을 등록합니다.
- 학생 삭제: 학번으로 학생을 삭제합니다.
- 학생 정보 조회: 특정 학번의 학생 정보를 조회합니다.
- 모든 학생 정보 조회: 등록된 모든 학생의 정보를 표시합니다.
- 성적 입력: 특정 학생의 과목별 성적을 입력합니다.
- 최고 평균 학생 조회: 가장 높은 평균 점수를 가진 학생을 조회합니다.
- 파일 저장/불러오기: CSV 또는 JSON 형식으로 데이터를 저장하거나 불러옵니다.
- 사용자가 '0'을 입력하면 프로그램이 종료됩니다.
이 프로그램은 파이썬의 거의 모든 기본 개념을 포함하고 있으며, 실제 학생 관리 시스템의 기본 기능을 구현하고 있습니다. 변수, 조건문, 반복문, 함수, 클래스, 파일 입출력 등 파이썬의 핵심 기능을 모두 사용하여 만들어졌습니다.
결과
===== 학생 성적 관리 시스템 =====
1. 학생 추가
2. 학생 삭제
3. 학생 정보 조회
4. 모든 학생 정보 조회
5. 성적 입력
6. 최고 평균 학생 조회
7. CSV 파일로 저장
8. CSV 파일에서 불러오기
9. JSON 파일로 저장
10. JSON 파일에서 불러오기
0. 종료
==========================
메뉴 선택:
'코딩교육 > Python 초등교육에서 전문가까지' 카테고리의 다른 글
2단계 : 6. 실습 : 파이썬 파일 관리 시스템 (0) | 2025.04.02 |
---|---|
2단계 : 6. 파일 작업 중 예외 처리 (파일이 없는 경우) (0) | 2025.04.01 |
2단계 : 6. 파일 작업 후 반드시 닫기 - close() 와 with open의 차이와 선택기준 (0) | 2025.03.31 |
2단계 : 6. 파일 쓰기 - write() 와 writelines 완벽 이해 (0) | 2025.03.30 |
2단계 : 6. 파일 읽기 - read(), readline(), readlines() (0) | 2025.03.28 |