14. 项目大结局

添加项目主模块:main.py

import school

school.load_from_csv_file()
school.class_manager()

已经完成的主要模块

学校模块

school.py

主要数据结构和方法:

班级模块

class_room.py

主要数据结构和方法:

学生模块

student.py

主要数据结构和方法:

主模块

main.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)
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()
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()
class Student:
    '''学生类型'''
    def __init__(self, name, chinese, math):
        self.name = name
        self.chinese_score = chinese
        self.math_score = math

优缺点

优点

缺点

缺点的改进型存储方法

班级表:

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
...
...
...