#xu#True
python
"""
学生成绩管理系统
功能:管理学生信息,计算成绩统计
作者:AI助手
版本:1.0
"""
# ==================== 导入模块 ====================
import json # 用于JSON数据操作
from typing import List, Dict, Optional # 类型提示,提高代码可读性
from datetime import datetime # 日期时间处理
# ==================== 常量定义 ====================
MAX_SCORE = 100 # 最高分数
MIN_SCORE = 0 # 最低分数
PASS_SCORE = 60 # 及格分数线
DATA_FILE = "students.json" # 数据存储文件名
# ==================== 类定义 ====================
class Student:
"""
学生类
用于表示单个学生的信息和成绩
属性:
name (str): 学生姓名
student_id (str): 学号
scores (Dict[str, float]): 各科成绩字典
"""
def __init__(self, name: str, student_id: str):
"""
初始化学生对象
参数:
name: 学生姓名
student_id: 学号,格式应为"20230001"
异常:
ValueError: 当学号长度不为8时抛出
"""
if len(student_id) != 8:
raise ValueError("学号长度必须为8位")
self.name = name
self.student_id = student_id
self.scores = {} # 初始化为空字典
self.created_at = datetime.now() # 记录创建时间
def add_score(self, subject: str, score: float) -> bool:
"""
添加或更新科目成绩
参数:
subject: 科目名称
score: 分数,应在0-100之间
返回:
bool: 操作是否成功
示例:
>>> student.add_score("数学", 95.5)
True
"""
# 参数验证
if not MIN_SCORE <= score <= MAX_SCORE:
print(f"错误:分数必须在{MIN_SCORE}到{MAX_SCORE}之间")
return False
if not subject.strip(): # 检查科目名是否为空
print("错误:科目名称不能为空")
return False
# 添加成绩
self.scores[subject] = round(score, 1) # 保留一位小数
print(f"成功添加 {subject} 成绩: {score}")
return True
def calculate_average(self) -> Optional[float]:
"""
计算平均分
返回:
float: 平均分,如果没有成绩则返回None
"""
if not self.scores: # 检查字典是否为空
print(f"学生 {self.name} 暂无成绩")
return None
total = sum(self.scores.values())
average = total / len(self.scores)
return round(average, 2) # 保留两位小数
def is_pass(self) -> bool:
"""
判断学生是否及格(平均分>=60)
返回:
bool: 是否及格
"""
average = self.calculate_average()
if average is None:
return False
return average >= PASS_SCORE
def __str__(self) -> str:
"""
返回学生信息的字符串表示
返回:
str: 格式化后的学生信息
"""
avg_score = self.calculate_average()
status = "及格" if self.is_pass() else "不及格"
info_lines = [
f"学生信息:",
f" 姓名: {self.name}",
f" 学号: {self.student_id}",
f" 成绩单:"
]
# 添加各科成绩
for subject, score in self.scores.items():
info_lines.append(f" {subject}: {score}")
# 添加统计信息
if avg_score is not None:
info_lines.append(f" 平均分: {avg_score}")
info_lines.append(f" 状态: {status}")
return "\n".join(info_lines)
class StudentManager:
"""
学生管理器类
管理多个学生对象,提供批量操作
"""
def __init__(self):
"""初始化学生管理器"""
self.students: Dict[str, Student] = {} # 用学号作为键存储学生
def add_student(self, student: Student) -> bool:
"""
添加学生到管理器
参数:
student: Student对象
返回:
bool: 是否添加成功
"""
if student.student_id in self.students:
print(f"错误:学号 {student.student_id} 已存在")
return False
self.students[student.student_id] = student
print(f"成功添加学生: {student.name}")
return True
def find_student(self, student_id: str) -> Optional[Student]:
"""
根据学号查找学生
参数:
student_id: 学号
返回:
Student: 找到的学生对象,未找到返回None
"""
return self.students.get(student_id)
def calculate_class_average(self) -> float:
"""
计算全班平均分
返回:
float: 全班平均分
"""
if not self.students:
return 0.0
total_average = 0
count = 0
for student in self.students.values():
avg = student.calculate_average()
if avg is not None: # 只统计有成绩的学生
total_average += avg
count += 1
return round(total_average / count, 2) if count > 0 else 0.0
def save_to_file(self, filename: str = DATA_FILE) -> bool:
"""
将学生数据保存到JSON文件
参数:
filename: 文件名
返回:
bool: 保存是否成功
"""
try:
data = {
"students": [],
"metadata": {
"saved_at": datetime.now().isoformat(),
"total_students": len(self.students)
}
}
for student in self.students.values():
student_data = {
"name": student.name,
"student_id": student.student_id,
"scores": student.scores,
"created_at": student.created_at.isoformat()
}
data["students"].append(student_data)
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"数据已保存到 {filename}")
return True
except (IOError, TypeError) as e:
print(f"保存文件失败: {e}")
return False
def load_from_file(self, filename: str = DATA_FILE) -> bool:
"""
从JSON文件加载学生数据
参数:
filename: 文件名
返回:
bool: 加载是否成功
"""
try:
with open(filename, 'r', encoding='utf-8') as f:
data = json.load(f)
self.students.clear() # 清空当前数据
for student_data in data.get("students", []):
student = Student(
name=student_data["name"],
student_id=student_data["student_id"]
)
student.scores = student_data.get("scores", {})
# 注意:实际项目中需要处理日期转换
self.students[student.student_id] = student
print(f"从 {filename} 加载了 {len(self.students)} 名学生")
return True
except FileNotFoundError:
print(f"文件 {filename} 不存在")
return False
except (json.JSONDecodeError, KeyError) as e:
print(f"文件格式错误: {e}")
return False
# ==================== 工具函数 ====================
def display_menu() -> None:
"""
显示主菜单
返回:
None
"""
menu_items = [
"=" * 40,
"学生成绩管理系统",
"=" * 40,
"1. 添加学生",
"2. 添加成绩",
"3. 查看学生",
"4. 查看所有学生",
"5. 计算统计信息",
"6. 保存数据",
"7. 加载数据",
"8. 退出系统",
"=" * 40
]
print("\n".join(menu_items))
def get_valid_input(prompt: str, input_type=str, validation_func=None) -> any:
"""
获取有效的用户输入
参数:
prompt: 提示信息
input_type: 期望的输入类型
validation_func: 自定义验证函数
返回:
验证后的输入值
"""
while True:
try:
user_input = input(prompt).strip()
# 类型转换
if input_type != str:
user_input = input_type(user_input)
# 自定义验证
if validation_func and not validation_func(user_input):
print("输入不符合要求,请重新输入")
continue
return user_input
except ValueError:
print(f"错误:请输入有效的{input_type.__name__}类型")
except KeyboardInterrupt:
print("\n用户中断操作")
raise
# ==================== 主程序 ====================
def main():
"""
主函数
程序的入口点,管理主要流程
"""
manager = StudentManager()
print("欢迎使用学生成绩管理系统")
while True:
try:
display_menu()
choice = get_valid_input(
"请选择操作 (1-8): ",
input_type=int,
validation_func=lambda x: 1 <= x <= 8
)
if choice == 1: # 添加学生
name = get_valid_input("请输入学生姓名: ")
student_id = get_valid_input(
"请输入学号 (8位数字): ",
validation_func=lambda x: x.isdigit() and len(x) == 8
)
try:
student = Student(name, student_id)
if manager.add_student(student):
print("添加成功!")
except ValueError as e:
print(f"创建学生失败: {e}")
elif choice == 2: # 添加成绩
student_id = get_valid_input("请输入学号: ")
student = manager.find_student(student_id)
if student:
subject = get_valid_input("请输入科目名称: ")
score = get_valid_input(
f"请输入{subject}成绩 (0-100): ",
input_type=float,
validation_func=lambda x: MIN_SCORE <= x <= MAX_SCORE
)
student.add_score(subject, score)
else:
print("未找到该学生")
elif choice == 3: # 查看单个学生
student_id = get_valid_input("请输入学号: ")
student = manager.find_student(student_id)
if student:
print("\n" + str(student))
else:
print("未找到该学生")
elif choice == 4: # 查看所有学生
if not manager.students:
print("当前没有学生记录")
continue
print(f"\n共有 {len(manager.students)} 名学生:")
for i, student in enumerate(manager.students.values(), 1):
print(f"\n{i}. {student.name} ({student.student_id})")
avg = student.calculate_average()
if avg:
print(f" 平均分: {avg}, 状态: {'及格' if student.is_pass() else '不及格'}")
elif choice == 5: # 计算统计信息
class_avg = manager.calculate_class_average()
pass_count = sum(1 for s in manager.students.values() if s.is_pass())
print("\n班级统计信息:")
print(f" 学生总数: {len(manager.students)}")
print(f" 及格人数: {pass_count}")
print(f" 不及格人数: {len(manager.students) - pass_count}")
print(f" 班级平均分: {class_avg}")
elif choice == 6: # 保存数据
manager.save_to_file()
elif choice == 7: # 加载数据
manager.load_from_file()
elif choice == 8: # 退出
save_choice = get_valid_input(
"是否保存数据后退出? (y/n): ",
validation_func=lambda x: x.lower() in ['y', 'n']
)
if save_choice.lower() == 'y':
manager.save_to_file()
print("感谢使用,再见!")
break
# 操作间隔
input("\n按回车键继续...")
except KeyboardInterrupt:
print("\n\n程序被用户中断")
break
except Exception as e:
print(f"发生未知错误: {e}")
print("程序将继续运行...")
# ==================== 程序入口 ====================
if __name__ == "__main__":
"""
这是程序的入口点。
当直接运行此脚本时,会执行main()函数。
当作为模块导入时,不会自动运行。
"""
main()