1. 场景描述
学霸一词是近年来流行的网络用语,关于学霸的定义网络上也有不同的版本解释,实际上这是一个见仁见智的问题。在我看来,学霸应该具备的三个特点:首先学霸是品学兼优学生;其次是思维灵活、学习力强;最后是考试成绩稳定、名列前茅。学霸是老师的骄傲,学霸绝对是众多同学心目中的yyds,是对标学习的榜样,当然学霸也是某些同学羡慕嫉妒恨的对象。在学校,老师要通过考试来检验教学效果,通过对学生考试成绩和排名分析,了解学生的学习情况,制订学生个性化提升计划,同时也要通过排名分析表扬先进,鞭策后进,实现和达到提升学习成绩的教学目标。 下面我们就使用Python编写一个学生成绩统计分析程序,以帮助老师分析学生的考试成绩,制订教学计划,同时也有利于学生对标学习,追赶学霸。
2. 编程思路
我们可以使用Python对象编程,实现学生成绩统计分析。定义两个类:一个是学生类Student,另一个为学霸类BestStudents。详细说明如下:
2.1 Student类
属性包括:学生姓名、学生所选科目名称及成绩,可以字典形式存放科目和成绩分数。 方法包括以下内容: get_name():获取学生姓名; get_total():计算学生各科成绩的总分; get_score(subject):获取学生单科分数,subject代表科目; elective(subject):判断学生是否选修某科目,这里的参数subject表示科目名称; print_student():打印学生各科成绩和分数。
2.2 BestStudnets类
学霸类BestStudets包括以下属性: 选择学霸的人数,学生信息列表,其中的学生信息包含姓名、各科成绩分数。 学霸类BestStudents包含以下方法: top_total():找出总成绩前5名的学生,这里把他们称之为学霸。 top_subject(subject):找出单科成绩前5名的学生,参数subject代表学科名称。
2.3 学生成绩存放
我们把学生的成绩保存到文本文件students.txt中,内容如下所示: 以上列出了13位同学在某次期末考试中的成绩分数。在这个文本文件中,每一列之间使用制表符‘\t’进行分隔。语文、数学和外语每个科目满分为150分,其他科目满分100分。每个学生考试科目为6个学科,语文、数学和外语为必考科目,其它为选修科目。我们作如下约定:凡是成绩为0分的科目,代表该学生的未选修科目。
2.4 学生成绩加载
此外我们需要从文本文件students.txt读入学生成绩,供后续分析使用。 下面我们就可以进入程序编码阶段。
3. 程序代码
程序代码有两个模块构成。students.py是基础功能模块,主要定义学生类和学霸类;best_students.py是主程序模块。具体代码如下所示:
"""
students.py : 赶超学霸基础模块
"""
class Student:
""" 定义学生类 """
def __init__(self, name, score_lst, column_lst):
self.name = name
self.scores = {}
for idx, score in enumerate(score_lst):
if score:
self.scores[column_lst[idx]] = score # ①
def get_name(self):
return self.name
def get_total(self):
""" 计算总分 """
score_list = self.scores.values() # ②
total = 0
for score in score_list:
total += score
return total
def get_score(self, subject):
""" 获取单科成绩 """
if self.elective(subject):
return self.scores[subject]
else:
return None
def elective(self, subject):
""" 是否选考科目 """
if subject in self.scores.keys():
return True
else:
return False
def print_student(self):
""" 打印学生成绩 """
print('姓名\t' + self.name)
print('总分\t' + str(self.get_total()))
for subject, score in self.scores.items(): # ③
print(subject + '\t' + str(score))
class BestStudents:
""" 找出学霸 """
def __init__(self, student_lst, numbers=5):
self.number = numbers
self.students = student_lst
def top_total(self):
""" 总分学霸 """
total_lst = [(stud.get_name(), stud.get_total()) for stud in self.students] # ④
total_lst.sort(key=lambda stud: stud[1], reverse=True) # ⑤
return total_lst[:self.number]
def top_subject(self, subject):
""" 单科学霸 """
# 获取选考subject科目学生成绩
subject_lst = [(stud.get_name(), stud.get_score(subject)) for stud in self.students
if stud.elective(subject)] # ⑥
# 按成绩进行降序排序
subject_lst.sort(key=lambda stud: stud[1], reverse=True)
return subject_lst[:self.number]
重要语句说明如下: 语句①属性scores是一个字典,键是学科名称,值是成绩分数; 语句②取字典scores的成绩分数,生成新的列表; 语句③循环取出字典中的学科名称和成绩分数; 语句④使用列表推导式生成包含学生姓名和总分的元组列表,即列表的每一个元素是元组,这个元组有学生姓名和成绩总分构成。 语句⑤对含有元组元素的列表进行排名,使用学生的成绩总分作为键进行降序排序。 语句⑥获取选考subject科目的学生成绩,生成一个列表,其元素是包括学科名称和成绩分数的元组。
"""
best_students.py : 赶超学霸
"""
from common.students import * # ①
STUDENTS_DATA = 'students.txt'
def load_students(file_name):
""" 从文件中加载学生成绩 """
student_lst = []
infile = open(file_name, encoding='utf8', mode='r')
# 取表头的列名
while True:
line = infile.readline().strip()
# 过滤掉表头前空行
if line:
column_lst = line.split('\t')[1:]
break
# 获取姓名及各科成绩
for line in infile:
if line.strip():
# 过滤空行
stud_name, *score_lst = line.strip().split('\t')
score_lst = [float(score) for score in score_lst]
student_lst += [Student(stud_name, score_lst, column_lst)]
infile.close()
return student_lst
def rank_list(subject, top_stud):
""" 打印排行榜 """
title = subject + '排行榜'
print(title.center(20))
print('=' * 25)
for idx, (name, score) in enumerate(top_stud):
print('第{0}名\t'.format(idx+1) + name.strip() + '\t' + str(score))
print()
def find_student(stud_lst, name):
"""查询学生信息"""
status = False
for stud in stud_lst:
if stud.get_name() == name.strip():
stud.print_student()
status = True
break
if not status:
print('{0}:没有学生信息!'.format(name))
def main():
stud_list = load_students(STUDENTS_DATA) # ②
best_stud = BestStudents(stud_list) # ③
rank_list('总分', best_stud.top_total()) # ④
# 数学排行榜
rank_list('数学', best_stud.top_subject('数学')) # ⑤
rank_list('历史', best_stud.top_subject('历史'))
rank_list('地理', best_stud.top_subject('地理'))
rank_list('政治', best_stud.top_subject('政治'))
print('学生成绩'.center(20))
print('=' * 25)
find_student(stud_list, '李博闻')
print('-' * 25)
find_student(stud_list, '周立可')
if __name__ == '__main__':
main()
主要函数说明: 函数load_students():从文本文件中加载学生各学科成绩; 函数rank_list(subject, top_stud):打印排行榜; 函数find_student(stud_lst, name):查询学生的成绩分数。 重要语句说明: 语句①从包common中导入模块students中的所有函数; 语句②从文本文件students.txt中读入学生成绩; 语句③创建BestStudents类的实例best_stud; 语句④生成成绩总分的排行榜,取前五名; 语句⑤生成数学成绩排行榜,取前五名。
4. 运行效果
4.1 程序存放目录
D:\cases\赶超学霸>dir
2022/12/10 15:33 2,141 best_students.py
2022/12/10 16:22 <DIR> common
2022/12/10 15:58 972 students.txt
D:\cases\赶超学霸>
D:\cases\赶超学霸>cd common
D:\cases\赶超学霸\common>dir
2022/12/10 16:22 2,095 students.py
2022/04/01 07:34 106 __init__.py
D:\cases\赶超学霸\common>
4.2 执行效果
D:\cases\赶超学霸>python best_students.py
总分排行榜
=========================
第1名 李博闻 741.0
第2名 邱荷 720.0
第3名 李拓 695.0
第4名 柳湘莲 693.0
第5名 周立可 686.0
数学排行榜
=========================
第1名 李博闻 150.0
第2名 张冲之 149.0
第3名 柳湘莲 145.0
第4名 邱荷 145.0
第5名 姜雪梅 142.0
历史排行榜
=========================
第1名 万沐春 99.0
第2名 柳湘莲 98.0
第3名 周立可 98.0
第4名 邱荷 96.0
第5名 黄珊 95.0
地理排行榜
=========================
第1名 白若溪 95.0
第2名 万沐春 95.0
第3名 周立可 88.0
第4名 李拓 87.0
第5名 邱荷 87.0
政治排行榜
=========================
第1名 李博闻 99.0
第2名 黄珊 85.0
第3名 柳湘莲 83.0
第4名 姜雪梅 83.0
第5名 吕静成 79.0
学生成绩
=========================
姓名 李博闻
总分 741.0
语文 145.0
数学 150.0
外语 147.0
物理 100.0
政治 99.0
化学 100.0
-------------------------
姓名 周立可
总分 686.0
语文 143.0
数学 140.0
外语 125.0
历史 98.0
地理 88.0
生物 92.0
D:\cases\赶超学霸>
5. 程序优化
我们可以对当前的程序版本进一步进行优化,主要包括两个方面。一是使用Excel文件格式保存学生成绩分数的原始数据,以代替原来的文本文件格式;二是以统计图表方式展示学霸排行榜,以取代目前的文字显示,使显示的内容更加丰富和直观。