14. 项目大结局
添加项目主模块:main.py
import school
school.load_from_csv_file()
school.class_manager()
已经完成的主要模块
学校模块
school.py
主要数据结构和方法:
- class_rooms = []
- 操作班级的函数。
班级模块
class_room.py
主要数据结构和方法:
- 类:ClassRoom,班级数据和操作班级和管理学生的方法。
学生模块
student.py
主要数据结构和方法:
- 类:Student,用来保存学生数据。
主模块
main.py
作用
- 加载 csv 文件里面的数据,初始化管理系统。
- 调用 school 模块里的 class_manager 函数实现班级管理。
以下是项目完整代码(无删减)
- 工具模块:
tools.py
def get_display_width(s):
return sum([1 if ord(ch) < 128 else 2 for ch in s])
def center_to_display_width(s, width):
'''将字符串s的左右两端添加空格,使其达到width的显示宽度!
s = 'ABC中文', width = 10
返回:' ABC中文 '
'''
s_width = get_display_width(s) # 得到当前字符的显示宽度
# 计算需要补充的空格数
fill_blank_count = width - s_width
return s.center(len(s) + fill_blank_count)
- 学校相关模块:
school.py
import csv
from class_room import ClassRoom
import tools
class_rooms = [] # 用于存放班级对象
def add_class_room():
'''添加班级'''
class_name = input('请输入班级名称: ')
# 判断 class_name 不能超过 10 个显示字符的宽度
if tools.get_display_width(class_name) <= 10:
cr = ClassRoom(class_name)
class_rooms.append(cr)
print('添加班级', class_name, '成功!')
else:
print('添加班级失败,班级名太长!')
import time
time.sleep(2)
def list_all_class_room():
print('+------+------------+')
print('| 序号 | 班级名称 |')
print('+------+------------+')
number = 1
for cr in class_rooms:
print('| %4d | %s |' % (number, tools.center_to_display_width(cr.class_name, 10)))
print('+------+------------+')
number += 1
def del_class_room():
'''删除班级'''
list_all_class_room()
number = int(input('请输入删除班级的序号: '))
index = number - 1 # 对应列表的索引
if 0 <= index < len(class_rooms):
del class_rooms[index]
print('删除成功!')
else:
print('您输入的序号有误,删除失败!')
import time
time.sleep(2)
def enter_class_manager():
'''进入管理班级界面'''
list_all_class_room()
number = int(input('请输入一个要管理班级的序号: '))
index = number - 1
if index < 0 or index >= len(class_rooms):
print('您输入的班级序号有误!')
return
cr = class_rooms[index]
cr.student_manager()
def list_class_room_order_by_average_score():
'''列出班级排名(平均成绩高 - 低)'''
def get_avg_score(class_r):
return class_r.get_average_score()
result = sorted(class_rooms, key=get_avg_score, reverse=True)
print('+------+------------+--------+')
print('| 序号 | 班级名称 | 平均分 |')
print('+------+------------+--------+')
number = 1
for cr in result:
print('| %4d | %s | %5.1f |' % (
number,
tools.center_to_display_width(cr.class_name, 10),
cr.get_average_score()
))
number += 1
if len(result) :
print('+------+------------+--------+')
def save_to_csv_file(path_name='students.csv'):
'''保存班级信息'''
header = ['班级名称', '学生姓名', '语文成绩', '数学成绩']
file = open(path_name, 'w')
writer = csv.writer(file)
writer.writerow(header)
for cr in class_rooms:
cr.writer_to_csv_writer(writer)
file.close()
def load_from_csv_file(path_name='students.csv'):
'''加载班级信息'''
# 1. 清空之前班级的数据
class_rooms.clear()
# 2. 创建空集合,用来保存已经加载的班级名称,避免重复创建班级
class_room_set = set()
# 3. 打开文件并创建csv reader
file = open(path_name)
reader = csv.reader(file)
# 4. 读取每一行数据并创建班级对象和学生对象
first_line_flag = True # 记录是否是第一行的标记
for a_item in reader:
if first_line_flag:
first_line_flag = False
continue
if len(a_item) != 4:
print('文件', path_name, '不是此程序保存的合法的csv文件,加载失败')
break
class_name = a_item[0]
student_name = a_item[1]
chinese_score = int(a_item[2])
math_score = int(a_item[3])
if class_name not in class_room_set:
cur_class_room = ClassRoom(class_name)
class_room_set.add(class_name)
class_rooms.append(cur_class_room)
cur_class_room.add_student_by_info(
student_name, chinese_score, math_score)
# 5. 关闭文件
file.close()
def show_school_menu():
print(' xxxx小学信息管理系统')
print('+-----------------------------------+')
print('| 1) 添加班级 |')
print('| 2) 删除班级 |')
print('| 3) 进入管理班级 |')
print('| 4) 列出所用班级 |')
print('| 5) 列出班级排名(平均成绩高 - 低)|')
print('| 6) 保存班级信息 |')
print('| 7) 加载班级信息 |')
print('| 0) 退出程序 |')
print('+-----------------------------------+')
def class_manager():
'''此函数用来管理班级数据'''
while True:
show_school_menu()
sel = input('请选择:')
match sel:
case '1': # 1) 添加班级
add_class_room()
case '2': # 2) 删除班级
del_class_room()
case '3': # 3) 进入管理班级
enter_class_manager()
case '4': # 4) 列出所用班级
list_all_class_room()
case '5': # 5) 列出班级排名(平均成绩高 - 低)
list_class_room_order_by_average_score()
case '6': # 6) 保存班级信息
save_to_csv_file('students.csv')
case '7': # 7) 加载班级信息
load_from_csv_file('students.csv')
case '0': # 0) 退出程序
return
case _:
print('不存在的选项,请重新输入')
import time
time.sleep(2) # 让程序睡眠2秒
if __name__ == '__main__':
from student import Student
cr1 = ClassRoom('一年一班')
cr1.student.append(Student('张三', 100, 61))
cr1.student.append(Student('李四', 70, 81))
cr1.student.append(Student('王五', 90, 71))
cr1.student.append(Student('赵六', 80, 91))
class_rooms.append(cr1)
cr2 = ClassRoom('一年2班')
cr2.student.append(Student('张3', 7, 1))
cr2.student.append(Student('李4', 8, 2))
cr2.student.append(Student('王5', 9, 3))
cr2.student.append(Student('赵7', 6, 4))
class_rooms.append(cr2)
cr3 = ClassRoom('一年三班')
cr3.student.append(Student('aaa', 100, 99))
cr3.student.append(Student('bbb', 98, 98))
cr3.student.append(Student('cccc', 99, 97))
class_rooms.append(cr3)
cr4 = ClassRoom('一年4班')
cr4.student.append(Student('xxx', 60, 80))
cr4.student.append(Student('yyy', 70, 50))
class_rooms.append(cr4)
class_manager()
- 班级相关模块:
class_room.py
from student import Student
import tools
class ClassRoom:
'''班级类型'''
def __init__(self, class_name):
self.class_name = class_name # 班级名称
self.student = [] # 保存学生信息
def add_student(self):
student_name = input('请输入学生姓名: ')
if tools.get_display_width(student_name) >= 20:
print('学生的名字太长,添加失败!')
return
chinese_score = int(input('请输入学生的语文成绩: '))
if chinese_score < 0 or chinese_score > 100:
print('学生成绩不在合法范围内,添加失败!')
return
math_score = int(input('请输入学生的数学成绩: '))
if math_score < 0 or math_score > 100:
print('学生成绩不在合法范围内,添加失败!')
return
stu = Student(student_name, chinese_score, math_score)
self.student.append(stu)
print('添加学生', student_name, '成功!')
def modify_chinese_score(self):
'''修改语文成绩功能'''
self.list_all_student_info(self.student)
number = int(input('请输入要修改语文成绩的学生的序号:'))
index = number - 1
if index < 0 or index >= len(self.student):
print('您输入的序号有误,修改失败!')
return
a_student = self.student[index]
new_score = int(input('请输入' + a_student.name + '的新的语文成绩: '))
a_student.chinese_score = new_score
print('修改', a_student.name, '的语文成绩成功!')
def modify_math_score(self):
'''修改数学成绩功能'''
self.list_all_student_info(self.student)
number = int(input('请输入要修改数学成绩的学生的序号:'))
index = number - 1
if index < 0 or index >= len(self.student):
print('您输入的序号有误,修改失败!')
return
a_student = self.student[index]
new_score = int(input('请输入' + a_student.name + '的新的数学成绩: '))
a_student.math_score = new_score
print('修改', a_student.name, '的数学成绩成功!')
def del_student(self):
'''删除学生信息'''
self.list_all_student_info(self.student)
number = int(input('请选择要删除学生的序号: '))
index = number - 1
if index < 0 or index >= len(self.student):
print('您输入的序号有错,删除失败!')
return
del self.student[index]
print('删除学生成功!')
def list_all_student_info(self, student_list):
'''显示所有学生的信息'''
print('+------+----------------------+--------+--------+')
print('| 序号 | 姓名 |语文成绩|数学成绩|')
print('+------+----------------------+--------+--------+')
number = 1
for stu in student_list:
print('| %4d | %s | %4d | %4d |' % (
number, tools.center_to_display_width(stu.name, 20),
stu.chinese_score, stu.math_score))
number += 1
if len(student_list):
print('+------+----------------------+--------+--------+')
def list_student_info_order_by_chinese_score(self):
'''按语文成绩从高到低显示学生成绩'''
def get_chinese_score(a_student):
return a_student.chinese_score
result = sorted(self.student, key=get_chinese_score, reverse=True)
print('按语文成绩排序的列表')
self.list_all_student_info(result)
def list_student_info_order_by_math_score(self):
'''按数学成绩从高到低显示学生成绩'''
result = sorted(
self.student,
key=lambda a_stu: a_stu.math_score,
reverse=True)
print('按数学成绩排序的列表')
self.list_all_student_info(result)
def get_average_score(self):
if len(self.student) == 0:
return 0
total_score = 0
for a_student in self.student:
total_score += a_student.chinese_score + a_student.math_score
return total_score / (len(self.student) * 2)
def writer_to_csv_writer(self, csv_writer):
'''写入一个班级的学生数据'''
for a_stu in self.student:
a_item = [
self.class_name,
a_stu.name,
str(a_stu.chinese_score),
str(a_stu.math_score)
]
csv_writer.writerow(a_item)
def add_student_by_info(self, student_name, chinese_score, math_score):
a_stu = Student(student_name, chinese_score, math_score)
self.student.append(a_stu)
def show_class_menu(self):
'此函数用来显示操作菜单'
print(f' {self.class_name}-班级管理')
print('+-----------------------------------+')
print('| 1) 添加学生 |')
print('| 2) 修改学生的语文成绩 |')
print('| 3) 修改学生的数学成绩 |')
print('| 4) 删除学生 |')
print('| 5) 列出所有学生的成绩 |')
print('| 6) 按语文成绩从高到低显示学生成绩 |')
print('| 7) 按数学成绩从高到低显示学生成绩 |')
print('| 0) 退出班级 |')
print('+-----------------------------------+')
def student_manager(self):
'''此函数用来学生数据'''
while True:
self.show_class_menu()
sel = input('请选择:')
match sel:
case '1': # 1) 添加学生
self.add_student()
case '2': # 2) 修改学生的语文成绩
self.modify_chinese_score()
case '3': # 3) 修改学生的数学成绩
self.modify_math_score()
case '4': # 4) 删除学生
self.del_student()
case '5': # 5) 列出所有学生的成绩
self.list_all_student_info(self.student)
case '6': # 6) 按语文成绩从高到低显示学生成绩
self.list_student_info_order_by_chinese_score()
case '7': # 7) 按数学成绩从高到低显示学生成绩
self.list_student_info_order_by_math_score()
case '0': # 0) 退出班级
return
case _:
print('不存在的选项,请重新输入')
import time
time.sleep(2) # 让程序睡眠2秒
if __name__ == '__main__':
cr1 = ClassRoom('一年1班')
cr1.student.append(Student('张三', 100, 61))
cr1.student.append(Student('李四', 70, 81))
cr1.student.append(Student('王五', 90, 71))
cr1.student.append(Student('赵六', 80, 91))
print('平均分:', cr1.get_average_score())
cr1.student_manager()
- 学生相关模块:
student.py
class Student:
'''学生类型'''
def __init__(self, name, chinese, math):
self.name = name
self.chinese_score = chinese
self.math_score = math
优缺点
优点
- 模块化设计,设计思路清晰。
- 代码量少,功能齐全。
- 使用类和对象的设计,结构简单。
- 数据能够长期存储。
- 数据用excel可读。
缺点
- 学生只有两门成绩,难于扩展。
- 只适合一个学校的单机使用。
- 如果班级里面没有学生,则保存是会丢失班级信息,导致加载时缺少班级信息。
- 班级重名,保存后加载会合并班级。
- 没有异常处理机制,程序崩溃,数据丢失。
- 模块太多,应当封装成为包。
- 对象的属性没有封装,不安全。
缺点的改进型存储方法
班级表:
classes.csv
格式
班级ID
班级名称
1
一年一班
2
一年2班
学生表
student.csv
格式
班级ID
学生姓名
语文成绩
数学成绩
1
张三
100
99
1
李四
98
97
2
王五
96
95
2
赵六
94
93
改进为关系型数据库存储
班级表:
classes.csv
班级ID
班级名称
1
一年一班
2
一年2班
学生表
student.csv
学生ID
学生姓名
班级ID
1
张三
1
2
李四
1
3
王五
2
4
赵六
2
课程表
subject.csv
课程ID
课程
1
语文
2
数学
成绩表
score.csv
学生ID
课程ID
成绩
1
1
100
1
2
99
2
1
98
2
2
97
...
...
...