进阶 11:学生管理系统(基于面向对象)

代码结构构思

文件结构

student_management_system/
│
├── main.py       # 主函数入口
├── manager.py    # 学生管理类(增删改查功能)
└── models.py     # 学生模型类

功能描述

添加学生

  • 输入学号、姓名和年龄,新增一个学生。
  • 如果学号重复,则提示添加失败。

删除学生

  • 输入学号,根据学号删除学生。
  • 如果学号不存在,则提示删除失败。

修改学生信息

  • 输入学号,可选择修改学生的姓名和/或年龄。

查询学生信息

  • 根据学号查找并打印学生信息。

显示所有学生

  • 列出所有学生的详细信息。

退出系统

  • 结束程序运行。

扩展建议

持久化数据

  • 使用文件(如 JSONCSV)保存学生信息,退出系统时保存数据,下次运行时加载。

异常处理

  • 添加输入校验和异常捕获(如年龄输入非数字时提示用户)。

初级代码

下面是一个简单的学生管理系统的代码实现,仅仅使用面向对象实现了基本的功能

模型类:models.py

class Student:
    """
    学生模型类,包含学生的基本信息:姓名、年龄、学号
    """
    def __init__(self, student_id, name, age):
        self.student_id = student_id
        self.name = name
        self.age = age

    def __str__(self):
        return f"学号: {self.student_id}, 姓名: {self.name}, 年龄: {self.age}"

学生管理类:manager.py

from models import Student


class StudentManager:
    """
    学生管理类,提供增删改查功能
    """
    def __init__(self):
        self.students = []  # 存储所有学生对象的列表

    def add_student(self, student_id, name, age):
        """添加学生"""
        student = Student(student_id, name, age)
        self.students.append(student)
        print(f"添加成功: {student}")

    def remove_student(self, student_id):
        """根据学号删除学生"""
        for student in self.students:
            if student.student_id == student_id:
                self.students.remove(student)
                print(f"已删除: {student}")
                return
        print(f"学号为 {student_id} 的学生不存在")

    def update_student(self, student_id, name=None, age=None):
        """根据学号更新学生信息"""
        for student in self.students:
            if student.student_id == student_id:
                if name:
                    student.name = name
                if age:
                    student.age = age
                print(f"更新成功: {student}")
                return
        print(f"学号为 {student_id} 的学生不存在")

    def find_student(self, student_id):
        """根据学号查找学生"""
        for student in self.students:
            if student.student_id == student_id:
                print(f"找到学生: {student}")
                return student
        print(f"学号为 {student_id} 的学生不存在")
        return None

    def list_students(self):
        """列出所有学生"""
        if not self.students:
            print("当前没有学生信息")
        else:
            print("所有学生信息如下:")
            for student in self.students:
                print(student)

主函数入口:main.py

from manager import StudentManager


def print_menu():
    """打印菜单"""
    print("\n学生管理系统")
    print("1. 添加学生")
    print("2. 删除学生")
    print("3. 修改学生信息")
    print("4. 查询学生信息")
    print("5. 显示所有学生")
    print("6. 退出系统")


def main():
    manager = StudentManager()  # 创建学生管理对象

    while True:
        print_menu()
        choice = input("请选择操作(1-6): ")

        if choice == "1":
            student_id = input("请输入学号: ")
            name = input("请输入姓名: ")
            age = input("请输入年龄: ")
            manager.add_student(student_id, name, int(age))

        elif choice == "2":
            student_id = input("请输入要删除的学生学号: ")
            manager.remove_student(student_id)

        elif choice == "3":
            student_id = input("请输入要修改的学生学号: ")
            name = input("请输入新姓名(可留空跳过修改): ")
            age = input("请输入新年龄(可留空跳过修改): ")
            manager.update_student(student_id, name if name else None, int(age) if age else None)

        elif choice == "4":
            student_id = input("请输入要查询的学生学号: ")
            manager.find_student(student_id)

        elif choice == "5":
            manager.list_students()

        elif choice == "6":
            print("退出系统")
            break

        else:
            print("输入有误,请重新选择!")


if __name__ == "__main__":
    main()

添加扩展功能:

在基于基本功能的基础上,添加了持久化数据功能(使用 JSON 文件保存和加载学生信息)以及异常处理(包括输入校验和异常捕获),实现更可靠和功能完善的学生管理系统。

具体要求:

优化后的代码主要实现了以下几个功能:

  1. 数据持久化
    • 使用JSON文件来持久化学生数据,重新启动程序后,之前保存的学生信息仍然可以加载并使用。
    • StudentManager类中添加load_studentssave_students方法,用于在程序启动时加载数据和在退出时保存数据。
  2. 数据转换
    • Student类增加to_dictfrom_dict方法,以便学生对象与JSON数据之间进行转换。
  3. 输入验证
    • main.py中,添加get_valid_int函数来确保用户输入的年龄是一个有效的整数,避免程序崩溃。
  4. 异常处理
    • 在数据加载和保存过程中加入异常处理,确保即使数据文件不存在或者文件格式错误,程序也能继续运行。
    • 在数据保存时,如果出现其他异常情况,则会输出错误信息。
  5. 菜单修改
    • 更新菜单中的选项:退出系统改为“保存并退出系统”,提示用户保存数据。
  6. 逻辑优化
    • 更新学生信息时,进行更细致的输入验证,确保输入的年龄如果为空,则不会尝试转换成整数。

持久化数据功能如何实现?

data = [student.to_dict() for student in self.students]

这段代码是一个 列表推导式(List Comprehension),用于将 self.students(一个学生对象的列表)转换成包含学生字典的列表。下面逐步解析:

1. 基础部分:self.students

self.students 是一个存储 学生对象 的列表,例如:

self.students = [
    Student("001", "Alice", 18),
    Student("002", "Bob", 19)
]

这是一个包含 Student 对象的列表。

2. 调用 student.to_dict()

student.to_dict() 是一个方法,用于将 Student 对象转换为 字典

在代码中的 Student 类里,to_dict() 可以是这样定义的:

def to_dict(self):
    """将学生对象转换为字典"""
    return {"student_id": self.student_id, "name": self.name, "age": self.age}

调用 to_dict() 后,一个 Student 对象会变成这样的字典:

{"student_id": "001", "name": "Alice", "age": 18}

3. 列表推导式的作用

列表推导式将 self.students 中的每个 Student 对象转换成字典,并返回一个新列表。

代码含义:

data = [student.to_dict() for student in self.students]

等价的普通循环代码如下:

data = []
for student in self.students:
    data.append(student.to_dict())
  • 遍历 self.students 中的每个 student 对象。
  • 对每个 student 调用 to_dict() 方法,生成对应的字典。
  • 将所有字典组成一个新的列表,赋值给 data

示例: 假设 self.students 的内容为:

self.students = [
    Student("001", "Alice", 18),
    Student("002", "Bob", 19)
]

那么执行这段代码后,data 的值为:

data = [
    {"student_id": "001", "name": "Alice", "age": 18},
    {"student_id": "002", "name": "Bob", "age": 19}
]

这种转换通常用于 数据持久化数据传输,例如:

  • 将数据保存到 JSON 文件。
  • 将数据发送到 API 或数据库。

如何持久化字典到json 文件中?

例如,设置在 save_students() 方法中,使用这段代码将学生对象序列化为 JSON 数据:

with open(self.DATA_FILE, "w", encoding="utf-8") as file:
    data = [student.to_dict() for student in self.students]
    json.dump(data, file, ensure_ascii=False, indent=4)

结果是一个 JSON 文件:

[
    {
        "student_id": "001",
        "name": "Alice",
        "age": 18
    },
    {
        "student_id": "002",
        "name": "Bob",
        "age": 19
    }
]

如何加载已持久化的 json 文件中的内容转化为字典列表?

要将一个已持久化的 JSON 文件加载并转化为字典列表,可以使用 Python 的 json 模块。假设你的 JSON 文件中存储的数据是一个列表,其中每个元素都是一个字典,如你所描述的结构。以下是步骤和代码示例:

  1. 确保 JSON 文件的结构正确,数据内容看起来应该类似于:
   [
       {"student_id": "001", "name": "Alice", "age": 18},
       {"student_id": "002", "name": "Bob", "age": 19},
       {"student_id": "003", "name": "Charlie", "age": 17}
   ]
  1. 使用 Python 代码读取文件并加载为列表:
   import json

   # 假设你的 JSON 文件名为 'students.json'
   with open('students.json', 'r', encoding='utf-8') as file:
       data = json.load(file)

   # 打印加载的列表
   print(data)

在这个例子中,json.load(file) 函数会读取文件内容并将其解析为字典列表。请确保在使用 open() 函数时指定正确的文件路径和编码(通常为 utf-8,尤其是在处理可能包含非 ASCII 字符的数据时)。

这段代码,data 变量将包含文件中的数据

当然,我们可以选择优化一下代码,添加异常处理:

import json

# 假设 JSON 文件路径为 'students.json'
file_path = "students.json"

try:
    # 尝试打开并读取 JSON 文件
    with open(file_path, 'r', encoding='utf-8') as file:
        data = json.load(file)
        
        # 此时 data 已经是一个 Python 列表,包含字典元素
        print(data)
        
except FileNotFoundError:
    print(f"文件路径错误: {file_path} 找不到。")
except json.JSONDecodeError:
    print("JSON 格式错误,无法解析文件。")

输出结果:

进阶 11:学生管理系统(基于面向对象)

如何从字典转换为学生对象?

字典 转换为 Student 对象。可以使用一个 工厂方法,用来简化从外部数据结构创建 Student 实例的过程。

1. data 是什么?

data 是一个包含多个字典的列表,每个字典表示一个学生的信息。例如:

data = [
    {"student_id": "001", "name": "Alice", "age": 18},
    {"student_id": "002", "name": "Bob", "age": 19},
    {"student_id": "003", "name": "Charlie", "age": 17}
]

2. Student.from_dict(item)

def from_dict(data):
    """从字典转换为学生对象"""
    return Student(data["student_id"], data["name"], data["age"])

Student.from_dict(item) 是调用 Student 类中的静态方法,用字典 item 创建一个新的 Student 对象。假设 item 是:

{"student_id": "001", "name": "Alice", "age": 18}

Student.from_dict(item) 等价于:

Student("001", "Alice", 18)

3. 列表推导式

在这里:

  • 表达式Student.from_dict(item),表示将每个 item 转换为 Student 对象。
  • 变量item,表示 data 列表中的每一个字典。
  • 可迭代对象data,它是包含学生数据的字典列表。

最终,这段代码会返回一个由 Student 对象组成的新列表。

4. 完整流程

  • 对于 data 列表中的每个 item(即每个学生信息字典),都会调用 Student.from_dict(item),将其转换为 Student 对象。
  • 生成的新 Student 对象会被收集到一个列表中。
  • 最终,这个列表被赋值给 self.students,即 self.students 中存储了所有学生的对象。

我们可以先写一个简单的转化代码感受下,再带入实战:

class Student:
    def __init__(self, student_id, name, age):
        self.student_id = student_id
        self.name = name
        self.age = age
   
    @staticmethod
    def from_dict(data_slice):
        """从字典的切片中转换为学生对象"""
        return Student(data_slice["student_id"], data_slice["name"], data_slice["age"])

# 原始数据
data = [
    {"student_id": "001", "name": "Alice", "age": 18},
    {"student_id": "002", "name": "Bob", "age": 19},
    {"student_id": "003", "name": "Charlie", "age": 17}
]
# 转换为对象列表
students = [Student.from_dict(data_slice) for data_slice in data]

print(students)

输出结果:

进阶 11:学生管理系统(基于面向对象)

修改后代码内容:

1、模型类:models.py

模型类保持不变,表示学生的基本信息。

class Student:
    """
    学生模型类,包含学生的基本信息:姓名、年龄、学号
    """
    def __init__(self, student_id, name, age):
        self.student_id = student_id
        self.name = name
        self.age = age

    def __str__(self):
        return f"学号: {self.student_id}, 姓名: {self.name}, 年龄: {self.age}"

    def to_dict(self):
        """将学生对象转换为字典,便于持久化"""
        return {"student_id": self.student_id, "name": self.name, "age": self.age}

    @staticmethod
    def from_dict(data):
        """从字典转换为学生对象"""
        return Student(data["student_id"], data["name"], data["age"])

2. 学生管理类:manager.py

优化的学生管理类,支持加载和保存数据到 JSON 文件,并添加异常处理。

import json
from models import Student


class StudentManager:
    """
    学生管理类,提供增删改查功能,并支持数据持久化
    """
    DATA_FILE = "students.json"  # 保存数据的文件路径

    def __init__(self):
        self.students = []  # 存储所有学生对象的列表
        self.load_students()  # 初始化时加载数据

    def load_students(self):
        """从文件加载学生数据"""
        try:
            with open(self.DATA_FILE, "r", encoding="utf-8") as file:
                data = json.load(file)
                self.students = [Student.from_dict(item) for item in data]
            print("学生数据加载成功!")
        except FileNotFoundError:
            print("数据文件不存在,已创建新的数据文件。")
            self.students = []
        except json.JSONDecodeError:
            print("数据文件格式错误,已清空数据。")
            self.students = []

    def save_students(self):
        """将学生数据保存到文件"""
        try:
            with open(self.DATA_FILE, "w", encoding="utf-8") as file:
                data = [student.to_dict() for student in self.students]
                json.dump(data, file, ensure_ascii=False, indent=4)
            print("学生数据已保存!")
        except Exception as e:
            print(f"保存数据时出现错误:{e}")

    def add_student(self, student_id, name, age):
        """添加学生"""
        student = Student(student_id, name, age)
        self.students.append(student)
        print(f"添加成功: {student}")

    def remove_student(self, student_id):
        """根据学号删除学生"""
        for student in self.students:
            if student.student_id == student_id:
                self.students.remove(student)
                print(f"已删除: {student}")
                return
        print(f"学号为 {student_id} 的学生不存在")

    def update_student(self, student_id, name=None, age=None):
        """根据学号更新学生信息"""
        for student in self.students:
            if student.student_id == student_id:
                if name:
                    student.name = name
                if age:
                    student.age = age
                print(f"更新成功: {student}")
                return
        print(f"学号为 {student_id} 的学生不存在")

    def find_student(self, student_id):
        """根据学号查找学生"""
        for student in self.students:
            if student.student_id == student_id:
                print(f"找到学生: {student}")
                return student
        print(f"学号为 {student_id} 的学生不存在")
        return None

    def list_students(self):
        """列出所有学生"""
        if not self.students:
            print("当前没有学生信息")
        else:
            print("所有学生信息如下:")
            for student in self.students:
                print(student)

3. 主函数入口:main.py

主函数入口中添加了异常处理和输入校验,确保系统更加稳定。

from manager import StudentManager


def print_menu():
    """打印菜单"""
    print("\n学生管理系统")
    print("1. 添加学生")
    print("2. 删除学生")
    print("3. 修改学生信息")
    print("4. 查询学生信息")
    print("5. 显示所有学生")
    print("6. 保存并退出系统")


def get_valid_int(prompt):
    """获取有效的整数输入"""
    while True:
        try:
            value = int(input(prompt))
            return value
        except ValueError:
            print("输入无效,请输入一个整数!")


def main():
    manager = StudentManager()  # 创建学生管理对象

    while True:
        print_menu()
        choice = input("请选择操作(1-6): ")

        if choice == "1":
            student_id = input("请输入学号: ")
            name = input("请输入姓名: ")
            age = get_valid_int("请输入年龄: ")
            manager.add_student(student_id, name, age)

        elif choice == "2":
            student_id = input("请输入要删除的学生学号: ")
            manager.remove_student(student_id)

        elif choice == "3":
            student_id = input("请输入要修改的学生学号: ")
            name = input("请输入新姓名(可留空跳过修改): ")
            age = input("请输入新年龄(可留空跳过修改): ")
            manager.update_student(
                student_id, 
                name if name else None, 
                int(age) if age.isdigit() else None
            )

        elif choice == "4":
            student_id = input("请输入要查询的学生学号: ")
            manager.find_student(student_id)

        elif choice == "5":
            manager.list_students()

        elif choice == "6":
            manager.save_students()
            print("退出系统")
            break

        else:
            print("输入有误,请重新选择!")


if __name__ == "__main__":
    main()

代码改进点总结:

持久化功能

  • 使用 JSON 文件保存和加载学生信息,退出系统时自动保存数据,下次启动时自动加载。

异常处理

  • 提供输入校验,如验证年龄是否为整数。
  • 捕获文件操作中的异常(如文件不存在、JSON 格式错误)。
  • 对关键逻辑的异常进行友好提示。

代码可扩展性

  • Student 类支持字典与对象的转换,方便扩展到其他数据格式(如 CSV 或数据库)。
  • 数据文件路径 DATA_FILE 是可配置的。

优化代码算法

可以使用字典映射操作函数的方法,简化冗长的多分支 if-elif 逻辑。通过将用户输入的选项与对应的功能逻辑绑定到一个字典中,可以让代码更加简洁、清晰和易于维护。

优化后的主函数入口代码:main.py

from manager import StudentManager

def print_menu():
    """打印菜单"""
    print("\n学生管理系统")
    print("1. 添加学生")
    print("2. 删除学生")
    print("3. 修改学生信息")
    print("4. 查询学生信息")
    print("5. 显示所有学生")
    print("6. 保存并退出系统")


def get_valid_int(prompt):
    """获取有效的整数输入"""
    while True:
        try:
            value = int(input(prompt))
            return value
        except ValueError:
            print("输入无效,请输入一个整数!")


def add_student(manager):
    student_id = input("请输入学号: ")
    name = input("请输入姓名: ")
    age = get_valid_int("请输入年龄: ")
    manager.add_student(student_id, name, age)


def remove_student(manager):
    student_id = input("请输入要删除的学生学号: ")
    manager.remove_student(student_id)


def update_student(manager):
    student_id = input("请输入要修改的学生学号: ")
    name = input("请输入新姓名(可留空跳过修改): ")
    age = input("请输入新年龄(可留空跳过修改): ")
    manager.update_student(
        student_id,
        name if name else None,
        int(age) if age.isdigit() else None
    )


def find_student(manager):
    student_id = input("请输入要查询的学生学号: ")
    manager.find_student(student_id)


def list_students(manager):
    manager.list_students()


def save_and_exit(manager):
    manager.save_students()
    print("退出系统")
    exit()


def main():
    manager = StudentManager()  # 创建学生管理对象

    actions = {
        "1": add_student,
        "2": remove_student,
        "3": update_student,
        "4": find_student,
        "5": list_students,
        "6": save_and_exit,
    }

    while True:
        print_menu()
        choice = input("请选择操作(1-6): ")

        action = actions.get(choice)
        if action:
            action(manager)
        else:
            print("输入有误,请重新选择!")


if __name__ == "__main__":
    main()

优化后的特点

  1. 通过字典映射实现功能选择
    • 用户的输入选项(如 123 等)作为字典的键。
    • 功能函数(如 handle_add_student)作为字典的值。
    • 根据用户输入调用字典中的对应函数,避免了大量冗长的 if-elif 逻辑。
  2. 功能函数独立化
    • 每个功能模块(如添加学生、删除学生等)被封装成独立的函数。
    • 主函数只负责菜单显示和根据用户选择调用对应的功能函数,逻辑更加清晰。
  3. 支持扩展性
    • 如果需要添加新的功能,只需定义一个新的功能函数,并将其添加到 operations 字典中即可,无需修改主循环代码。
  4. 代码简洁且易于维护
    • 主循环中的逻辑只有两部分:打印菜单和调用对应的功能函数。
    • 函数间解耦,修改某个功能时不会影响其他功能。

字典来映射优化后续扩展功能示例

如果要新增功能,比如按年龄排序显示所有学生

  1. 定义一个新的功能函数:
def handle_sort_students_by_age(manager):
    """按年龄排序并显示所有学生"""
    sorted_students = sorted(manager.students, key=lambda s: s.age)
    print("按年龄排序的学生信息如下:")
    for student in sorted_students:
        print(student)

将新功能添加到 operations 字典中:

operations = {
    "1": handle_add_student,
    "2": handle_remove_student,
    "3": handle_update_student,
    "4": handle_find_student,
    "5": handle_list_students,
    "6": handle_exit,
    "7": handle_sort_students_by_age  # 新增功能
}

更新菜单打印函数:

def print_menu():
    print("\n学生管理系统")
    print("1. 添加学生")
    print("2. 删除学生")
    print("3. 修改学生信息")
    print("4. 查询学生信息")
    print("5. 显示所有学生")
    print("6. 保存并退出系统")
    print("7. 按年龄排序显示学生")

通过这种结构化设计,新功能的添加只需定义一个函数,并修改少量代码即可实现。

发布者:LJH,转发请注明出处:https://www.ljh.cool/42159.html

(0)
上一篇 2024年12月15日 下午6:47
下一篇 2024年12月22日 下午10:08

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注