第七十二题,简单版学生成绩管理系统
这题没有写成一坨脚本,而是拆成了两个各司其职的类。这是我从之前"学生类"、"银行账户类"一路摸爬滚打出来的直觉:数据归数据,管理归管理。
先上代码
实现一个简单的学生成绩管理系统,支持添加学生、记录学生成绩,并计算每个学生成绩的平均值
---------- 学生类 ----------
class Student:
"""用于表示一个学生及其成绩列表"""
def init(self, name):
self.name = name # 学生姓名
self.grades: listfloat = \[\] # 成绩列表,显式注解避免推断成 Any
def add_grade(self, grade):
"""添加一条学生成绩"""
self.grades.append(grade)
def calculate_average(self):
"""计算该学生成绩的平均值,无成绩时返回 0.0"""
if not self.grades:
return 0.0
return sum(self.grades) / len(self.grades)
def info(self):
"""汇总该学生的成绩信息"""
if not self.grades:
return f' {self.name}:尚未记录任何成绩'
average = self.calculate_average()
return (
f' {self.name}:共 {len(self.grades)} 条成绩 '
f'{self.grades},平均分 {average:.2f}'
)
---------- 学生成绩管理类 ----------
class StudentGradeManager:
"""学生成绩管理类,负责学生的增删查与成绩维护"""
def init(self):
键为学生姓名,值为 Student 对象
self.students: dictstr, Student = {}
def add_student(self, name):
if name in self.students:
print(f' 学生 {name} 已经存在,无需重复添加。')
return False
self.studentsname = Student(name)
print(f' 学生 {name} 添加成功。')
return True
def add_grade(self, name, grade):
if name not in self.students:
print(f' 查无此人:{name},请先添加该学生。')
return False
self.studentsname.add_grade(grade)
print(f' 已为 {name} 记录成绩 {grade}。')
return True
def show_average(self, name):
if name not in self.students:
print(f' 查无此人:{name},请先添加该学生。')
return False
student = self.studentsname
if not student.grades:
print(f' {name} 尚未记录任何成绩,无法计算平均分。')
return False
average = student.calculate_average()
print(f' {name} 的平均分为:{average:.2f}')
return True
def show_all(self):
print('\n' + '=' * 40)
print(f' 学生成绩汇总 (共 {len(self.students)} 人)')
print('=' * 40)
if not self.students:
print(' 系统中还没有任何学生。')
else:
for student in self.students.values():
print(student.info())
print('=' * 40)
---------- 输入辅助函数 ----------
def input_name(prompt):
"""输入姓名:不能为空"""
name = ''
valid = False
while not valid:
raw = input(prompt).strip()
if not raw:
print(' 输入无效 姓名不能为空,请重新输入。')
continue
name = raw
valid = True
return name
def input_grade(prompt):
"""输入成绩:必须是 0-100 之间的数字"""
grade = 0.0
valid = False
while not valid:
try:
value = float(input(prompt))
except ValueError:
print(' 输入无效 成绩必须是数字,请不要输入字母或符号。')
continue
if value < 0 or value > 100:
print(' 输入无效 成绩超出合理范围(0-100),请重新输入。')
continue
grade = value
valid = True
return grade
---------- 主程序 ----------
if name == 'main':
print('==== 欢迎使用简单版学生成绩管理系统 ====')
manager = StudentGradeManager()
while True:
print('\n请选择要执行的操作:')
print('1. 添加学生')
print('2. 为学生记录成绩')
print('3. 查询学生平均分')
print('4. 查看所有学生成绩')
print('0. 退出系统')
choice = input('请输入您的选择(0 / 1 / 2 / 3 / 4):').strip()
if choice == '1':
name = input_name(' 请输入要添加的学生姓名:')
manager.add_student(name)
elif choice == '2':
name = input_name(' 请输入要记录成绩的学生姓名:')
grade = input_grade(' 请输入该学生的成绩(0-100):')
manager.add_grade(name, grade)
elif choice == '3':
name = input_name(' 请输入要查询平均分的学生姓名:')
manager.show_average(name)
elif choice == '4':
manager.show_all()
elif choice == '0':
print('已退出系统,感谢使用,再见!')
break
else:
print(' 无效的选项,请输入 0、1、2、3 或 4。')
我的思路:各司其职,互不牵连
这套代码的骨架是两个类:
-
Student:只管"一个学生"的事------叫什么、考了几分、自己算自己的平均分。
-
StudentGradeManager:充当"教务处",用字典(键是姓名,值是 Student 对象)把所有人存起来,对外提供添加、记录、查询的入口。
这样设计的好处是:要改"平均分怎么算"只动 Student,要改"怎么找学生"只动管理类。
关键点一:修了原版的"越界"Bug
原版在计算平均分时,竟然去引用了一个不存在的 self.students(学生个人身上怎么会有全班学生的数据?)。一调就报错。
我把它改回了天经地义的样子:学生只算自己那份 sum(self.grades) / len(self.grades)。封装,就是管好自己,别瞎碰别人的数据。
关键点二:字典存储 + 存在性校验
管理类里,不管你是加成绩还是查平均分,我都先过一道"查无此人"的安检。不在字典里就提示,绝不让你报 KeyError 崩掉。查平均分时还多看一眼有没有成绩,空列表就老实提示。每步都有兜底。
关键点三:输入防呆(标志位循环)
姓名不能为空,成绩必须是在 0-100 的数字。这俩我都用了 while not valid 的标志位循环 + 循环外统一 return。
这不仅是为了输错不崩溃,还是为了绕开 PyCharm 的毛病------它老是把 while True 里的 return 误判为可能返回 None,搞得下游一堆警告。换成标志位,类型提示就清净了。成绩的 try/except 我也照旧把范围检查放在外面。
关键点四:菜单式"服务台"
主程序外面套个 while True 菜单,按选项分发,算完不清场,输 0 才退出。这就是把脚本变成能反复使用的小程序。