最近闲着无聊用Python写了个小练习,非常适合初学者,分享下代码。还有一个之前写的基础版的:「Python」学生管理系统(面向对象)

实现思路

一个采用面向对象的学生管理系统,学生作为一个对象Student(),管理系统也作为一个对象StudentManager()。包内包含三个文件,分别是:

  • main.py,启动文件
  • student.py,学生类文件
  • managerSystem.py,管理系统类文件

类或对象属性与方法分析

学生对象Student()主要包含一些属性值:

  • stu_id;
  • name;
  • gender;
  • tel;
  • address;
  • email.

管理对象StudentManager()主要包含一些方法,可以实现以下功能:

  • read_info()、save_info(),读取硬盘文件、保存内存中的信息到文件;
  • show_menu(),展示操作菜单;
  • add_stu(),添加单条学生信息;
  • edit_stu(),修改单条学生信息;
  • del_stu(),删除一条或者多条学生信息;
  • find_stu(),查询一条或者多条学生信息;
  • make_fake(self, n),传入参数n,可以生成n条假的学生信息;
  • make_id_list(),配合del_stu()find_stu()使用,帮助其实现同时对一条或者多条学生信息进行操作;
  • reorder_stu_id(),将学生ID重新排序,在每次删除学生信息后调用。

代码实现

main.py:

# -*- coding: utf-8 -*-

"""
@author: ManYacan
@Email: myxc@live.cn
@Website: www.manyacan.com
@time: 2022/04/20 19:18
"""
from managerSystem import *  # 导入管理系统模块

if __name__ == '__main__':
    # print('main.py已运行~')
    stu_manager = StudentManager()  # 创建对象
    stu_manager.run()  # 启动类的入口函数

student.py:

# -*- coding: utf-8 -*-

"""
@author: ManYacan
@Email: myxc@live.cn
@Website: www.manyacan.com
@time: 2022/04/20 19:20
"""

# import prettytable as pt


class Student(object):
    """
    定义一个学生类
    """

    def __init__(self, stu_id, name, gender, tel, address, email):
        """
        学生对象初始化函数
        :param name: 姓名
        :param gender: 性别
        :param tel: 手机号
        :param address: 地址
        :param email: 邮箱
        """
        self.id = stu_id
        self.name = name
        self.gender = gender
        self.tel = tel
        self.address = address
        self.email = email

    def __str__(self):
        """
        返回对象说明
        :return: 返回学生对象的信息
        """
        return f'{self.id}; {self.name}; {self.gender}; {self.tel}; {self.address}; {self.email}'


if __name__ == '__main__':
    # 测试类
    # student = Student('01', "张三", "男", "13033070911", "河南省宝丰县西大院", "myc@live.com")
    # print(student)

managerSystem.py:

# -*- coding: utf-8 -*-

"""
@author: ManYacan
@email: myxc@live.cn
@Website: www.manyacan.com
@time: 2022/04/20 19:21
"""

import random  # 配合Faker随机生成性别
import hues  # 可以输出带有颜色提示的信息,相当于高级一点的print()
from faker import Faker  # 用来制造一些假的学生信息
from student import *  # 导入学生类模块


class StudentManager(object):
    """
    管理系统类对象
    """

    def __init__(self):
        """
        对象的初始化
        """
        self.stu_list = []  # 存储内存读取的学员数据
        self.info_key = ['ID', 'Name', 'Gender', 'Phone', 'Address', 'Email']  # 需要统计或者展示的学生信息列表表头
        self.last_stu_id = 0  # 为每个学生定义一个ID号
        self.is_edited = False  # 记录是否对学生信息进行了修改,如果未作修改,只是查看,那么退出系统的时候不用进行保存提示

    def run(self):
        """
        类对象入口函数
        :return:
        """
        self.read_info()  # 读取文件信息
        hues.info("Welcome to use this student system.")  # 欢迎使用系统
        while True:  # 循环菜单操作
            self.show_menu()  # 显示菜单
            try:  # 这里为什么要使用try?因为如果输入字符,这里直接进行int()转换的话会报错
                command_num = int(input("Please input the command number:"))  # 输入指令
                if command_num == 1:  # 展示学生列表
                    self.show_table()
                elif command_num == 2:  # 添加学生
                    self.add_stu()
                elif command_num == 3:  # 修改学生信息
                    self.edit_stu()
                elif command_num == 4:  # 删除学生信息
                    self.del_stu()
                elif command_num == 5:  # 这里可以同时查看单个学生信息或者多个
                    self.find_stu(self.make_id_list())
                elif command_num == 6:  # 保存所有操作
                    self.save_info()
                elif command_num == 7:  # 生成虚假学生信息
                    self.make_fake(int(input("Please input the number that you want to generate:")))
                elif command_num == 8:  # 对学生ID进行重新排序,清除掉因为删除信息而造成的中间空掉的序号
                    self.reorder_stu_id()
                    pass
                elif command_num == 9:  # 退出系统
                    if self.is_edited:  # 如果对信息进行了修改,退出的时候询问是否保存
                        save_command = input("Do you want to save the student information?(y)")
                        if save_command == 'y':  # 输入”y“的话就对内存里的信息进行保存
                            # self.reorder_stu_id()
                            self.save_info()
                        else:
                            hues.warn('The information was edited, but it was not saved!')
                    else:
                        hues.info("The information was not edited.")
                    break
                else:
                    hues.error("Undefined Command number!")  # 打印错误信息

            except Exception as e:
                hues.error("Please enter the command number!")

    def read_info(self):
        """
        读取系统保存的文件信息
        :return:
        """
        try:
            f = open('student.json', 'r')  # 以只读的方式打开文件
        except:
            hues.log("Not find 'student.json', this system will creat it.")
            f = open('student.json', 'w')  # 如果读取不到,说明文件不存在,需要创建文件
        else:
            data = f.read()  # 读取文件
            if data != '' and data != '[]':
                # 如果程序第一次运行,打开了却没在文件中新增信息,那么就会创建一个空的文件,这个时候第二次启动程序因为data='',再进行eval()的话就会报错,所以要排除这种情况。如果读取到了data='',那么直接跳过
                read_info_list = eval(data)  # 读取到的是字符串,需要转化为列表
                self.stu_list = [Student(i['id'], i['name'], i['gender'], i['tel'], i['address'], i['email']) for i in
                                 read_info_list]  # 读取到的学生是一个字典,需要将字典转换成对象,然后存放到stu_list()列表中
                self.last_stu_id = int(read_info_list[-1]['id'])  # 获取最后一个学生的ID
                hues.success(f"Read [{len(read_info_list)}] student's information.")  # 打印下看看读取到了几条学生信息
            else:
                hues.info("'student.json' is empty.")
            f.close()  # 关闭文件

    @staticmethod
    def show_menu():
        """
        以表格的形式打印显示操作菜单
        :return:
        """
        tb = pt.PrettyTable()  # 创建一个美美表格的对象
        title_line = "+---------+------+-----+------+--------+------+------+------+---------+------+"  # 用来打印输出
        print(title_line)  # 打印线
        print("Student Management System".center(len(title_line), '-'))
        tb.field_names = ['Command', 'Show', 'Add', 'Edit', 'Delete', 'Find', 'Save', 'Fake', 'Reorder', 'Quit']
        tb.add_row([i for i in range(len(tb.field_names))])
        print(tb)

    def show_table(self):
        """
        以列表的形式展示所有学生信息,并以美美的表格的形式打印出来,得益于stu_list()函数的完善,这个函数的实现很简单
        :return:
        """
        if len(self.stu_list):  # 当学生列表里有元素时
            id_list = [i.id for i in self.stu_list]  # 创建一个列表用于存放所有的学生姓名,遍历所有的学生姓名
            self.find_stu(id_list)  # 将学生姓名传递给find_stu()方法
            hues.success(f'There are [{len(self.stu_list)}] student information.')
        else:
            hues.info('There is no student!')

    def add_stu(self):
        """
        添加学生 name, gender, tel, address, email
        :return:
        """
        # 用户输入需要进行收集的学生信息
        name = input("Please input student's name:")
        gender = input("Please input student's gender:")
        tel = input("Please input student's tel:")
        address = input("Please input student's address:")
        email = input("Please input student's email:")
        # 使用Student类来添加学生,学生ID需要+1
        stu = Student((self.last_stu_id + 1), name, gender, tel, address, email)
        self.stu_list.append(stu)  # 在学生列表里追加一条学生信息
        self.is_edited = True  # 对信息进行了修改,打开开关
        hues.success(f"Add [{stu.name}]'s information successful!")

    def edit_stu(self):
        """
        修改学生信息
        :return:
        """
        edit_name = input("Please input the name that you want to edit:")
        for i in self.stu_list:
            if edit_name == i.name:  # 如果输入的删除名字存在于列表中,那么删除该学生信息
                i.name = input("Please enter new name:")
                i.gender = input("Please enter new gender:")
                i.tel = input("Please enter new tel:")
                i.address = input("Please enter new address:")
                i.email = input("Please enter new email:")
                hues.success(f"[{i.name}]'s information have been updated.")
                self.find_stu([i.id])
                self.is_edited = True  # 对信息进行了修改,打开开关
                break
        else:  # 遍历了学生列表没有查找到学生,说明没有当前学生
            hues.error(f"Not find this student: [{edit_name}]!")

    def del_stu(self):
        """
        删除学生
        :return:
        """
        id_list = self.make_id_list()  # 获取用户输入操作的ID列表
        del_success_num = len(id_list)  # 记录删除了多少条学生信息,因为ID列表里的ID有可能是不存在的,因此先记录下,当不存在的时候就减去1
        hues.warn(f"Start to delete {len(id_list)} student information...")
        for stu_id in id_list:
            for i in self.stu_list:
                if stu_id == i.id:  # 如果输入的删除名字存在于列表中,那么删除该学生信息
                    hues.log(f"Delete [{stu_id}] successful!")
                    # self.find_stu([i.id])
                    self.stu_list.remove(i)
                    self.is_edited = True  # 对信息进行了修改,打开开关
                    break
            else:  # 遍历了学生列表没有查找到学生,说明没有当前学生
                del_success_num = del_success_num - 1  # 当ID不存在的时候就-1
                hues.error(f"Not find this student: [{stu_id}]!")
        hues.success(f"Delete {del_success_num} student information.")  # 打印下一共操作了多少条信息
        # self.reorder_stu_id()  # 删除的学生信息可能是中间的,例如存在ID:1,2,3,4,如果删除了ID2,3,那么就要将所有学生的ID重排序为1,2

    def find_stu(self, ids):
        """
        查找学生信息,并以表格的形式打印
        :param ids: 这个参数是list形式,里面元素都是int
        """
        tb = pt.PrettyTable()  # 创建一个美美表格的对象,用来美化显示打印
        tb.field_names = self.info_key
        for stu_id in ids:
            for i in self.stu_list:
                if stu_id == i.id:  # 如果找到了查找的学生
                    tb.add_row([i.id, i.name, i.gender, i.tel, i.address, i.email])
                    break
            else:  # 遍历了学生列表没有查找到学生,说明没有当前学生
                hues.error(f"Not find this student ID:[{stu_id}]!")
        print(tb)

    def save_info(self):
        """
        保存文件
        :return:
        """
        # stu_list中的学生都是对象,需要循环取出所有对象的属性和属性值,然后转化为字符串写入文件,写入的时候需要注意,需要把字符串中的“'”换成““”,这样在json文件中才能识别;还有就是地址过长时,自动生成的字符串中会包含换行符,需要进行替换掉
        f = open("student.json", 'w')
        f.write(str([i.__dict__ for i in self.stu_list]).replace('\'', '"'))
        self.is_edited = True  # 对信息进行了修改,打开开关
        hues.success(f'Write {len(self.stu_list)} information...')

    def make_fake(self, n):
        """
        生成几个虚假学生信息
        :return:
        """
        fake = Faker()
        fake_gender_list = ['W', 'M']  # 随机性别列表
        for i in range(n):
            self.last_stu_id += 1  # ID不能重复,每次使用前需要+1
            # 循环添加虚假的学生信息,fake.address()默认中间会有换行符,需要替换掉
            fake_stu = Student(self.last_stu_id, fake.name(), random.choice(fake_gender_list), fake.phone_number(),
                               fake.address().replace("\n", ' '),
                               fake.email())
            self.stu_list.append(fake_stu)
        hues.success(f'Generate [{n}] fake student information.')
        self.is_edited = True  # 对信息进行了修改,打开开关
        hues.warn("If you want to save generated information, you should use command number:6.")

    @staticmethod
    def make_id_list():
        """
        这个方法可以获取用户输入的字符串,然后将其转化成一个学生ID列表
        例如:
            1、输入”1“,转化成[1]
            2、输入”1,2,3“,转化成[1,2,3]
            3、输入”1-3“,转化成[1,2,3]
        :return: id_list:一个存储学生ID的list
        """
        hues.info(
            "If you want to find two or more student, please use ',' or '-' to split. For example: '1,2,3', '1-3'")
        find_id = input("Please input the id that you want to do:")
        if "," in find_id:  # 说明输入的是多个名字,需要分隔成列表
            id_list = find_id.split(',')  # 获取的字符串需要进行分割
            for i in range(len(id_list)):  # 分割完成后字符串里的元素都是字符串类型的,需要全部进行转换成int,
                id_list[i] = int(
                    id_list[i])  # 因为find_stu()函数内部与self.stu_list中的对象进行对比的时候,student对象的id是int类型的
        elif '-' in find_id:
            id_start, id_end = find_id.split('-')
            id_start, id_end = int(id_start), int(id_end)
            id_list = []
            for i in range(id_start, id_end + 1):
                id_list.append(i)
        else:  # 说明只输入了一个ID
            id_list = [int(find_id)]
        return id_list

    def reorder_stu_id(self):
        """
        对学生的ID进行重新排列:如果按照正常操作的话,学生ID是一个接着一个的,但是如果对中间的进行删除,那么中间缺失的数字就会空出来。
        :return:
        """
        for i in range(len(self.stu_list)):
            self.stu_list[i].id = i + 1
        self.is_edited = True  # 对信息进行了修改,打开开关
        hues.success("Reorder the student's ID.")


# DEBUG
if __name__ == '__main__':
    manager_demo = StudentManager()  # 创建一个对象
    # manager_demo.run()  # 启动对象的入口函数