☰
Python学生管理系统实战:从增删查到数据持久化
2026/10/8 18:03:29 网站建设 项目流程

这个项目是一个命令行版本的学生管理系统,主要实现:

新增学生 显示学生 查找学生 删除学生 存档到文件

整个程序虽然不算复杂,但是里面已经包含了一个完整小程序应该有的基本结构。


一、先确定学生管理系统要做什么

程序启动之后,先显示一个菜单,让用户选择操作。

菜单可以设计成:

1. 新增学生信息 2. 显示所有同学信息 3. 根据名字查找学生信息 4. 删除学生信息 0. 退出程序

然后不断读取用户输入,根据不同的数字进入不同的功能。

这种程序很适合使用:

whileTrue:

让菜单一直运行。

如果用户输入0,直接退出程序。


二、学生数据怎么保存?

这是写这个项目时我觉得最关键的一步。

一个学生肯定不只是一个数据。

比如一个学生至少有:

学号 姓名 性别 班级

如果给每个学生都创建四个独立变量:

studentId=...name=...gender=...className=...

学生一多就很难管理。

所以这里可以使用字典表示一个学生。

例如:

student={'studentId':studentId,'name':name,'gender':gender,'className':className}

这样,一个字典就表示一个完整的学生信息。


三、多个学生怎么办?

一个学生用字典保存,那多个学生就可以使用列表。

程序中准备一个全局列表:

students=[]

每增加一个学生,就把对应的字典放进去:

students.append(student)

最终的数据结构其实就是:

students ↓ [ student1, student2, student3, ... ]

其中每一个student又是一个字典。

也就是:

列表 ↓ 多个字典 ↓ 每个字典保存一个学生的信息

这种设计其实非常自然,也把前面学到的list和dict结合起来了。


四、创建程序入口

程序可以设计一个main()作为入口函数。

整体逻辑大概是:

defmain():whileTrue:choice=menu()ifchoice==0:sys.exit()elifchoice==1:insert()elifchoice==2:show()elifchoice==3:find()elifchoice==4:delete()else:print("您的输入有误! 请重新输入!")

最后再调用:

main()

这样整个程序的组织结构就比较清楚了。

main()不负责具体实现每一个功能,而是负责“指挥”。

真正的功能分别交给:

menu() insert() show() find() delete()

去完成。


五、菜单函数

菜单本身单独封装成一个函数:

defmenu():print(' 1. 新增学生')print(' 2. 显示学生')print(' 3. 查找学生')print(' 4. 删除学生')print(' 0. 退出程序')choice=input(' 请输入您的选择: ')returnchoice

把用户的输入交给main()判断。


六、新增学生

新增学生的流程比较简单:

输入学号 ↓ 输入姓名 ↓ 输入性别 ↓ 输入班级 ↓ 检查数据 ↓ 创建字典 ↓ 加入 students

首先输入基本信息:

studentId=input("请输入学生的学号: ")name=input("请输入学生的姓名: ")gender=input("请输入学生的性别: ")className=input("请输入学生的班级: ")

性别这里还进行了简单的检查:

ifgendernotin('男','女'):print('性别输入的内容不符合要求, 新增失败!')return

如果输入不符合要求,就直接结束这次新增操作。

之后创建学生字典:

student={'studentId':studentId,'name':name,'gender':gender,'className':className}

最后:

students.append(student)

把学生放进列表。


七、显示所有学生

有了:

students

之后,显示全部学生就很简单了。

直接遍历:

forsinstudents:

然后通过字典的 key 获取信息:

s['studentId']s['name']s['gender']s['className']

例如可以按照:

学号 姓名 性别 班级

这样的格式打印。

最后还可以使用:

len(students)

统计当前一共有多少条学生记录。

这个功能实际上就是:

遍历列表 ↓ 访问字典 ↓ 输出数据

八、根据姓名查找学生

查找功能需要先让用户输入一个名字:

name=input("请输入要查找的同学姓名: ")

然后遍历所有学生:

forsinstudents:

检查:

ifname==s['name']:

如果匹配,就把学生信息打印出来。

同时使用:

count+=1

记录一共找到了多少人。

这里有一个实际开发中的小特点:

姓名不一定唯一。

所以这里并没有找到第一个就结束,而是把整个列表遍历完,把所有同名学生都找出来。


九、删除学生

删除学生时采用学号进行查找。

流程:

输入学号 ↓ 遍历 students ↓ 找到对应学生 ↓ 从列表中删除

核心操作:

ifstudentId==s['studentId']:students.remove(s)

这里使用学号而不是姓名,也是因为学号更加适合作为学生的唯一标识。


十、为什么需要存档?

到目前为止,程序虽然可以完成:

新增 显示 查找 删除

但是还有一个很明显的问题:

程序一旦退出,之前的数据就没了。

因为现在的:

students=[]

本质上只是保存在程序运行期间的内存里。

所以需要加入“存档”功能,把学生信息保存到文件中。

这里约定使用:

record.txt

来保存学生数据。


十一、设计存档文件的格式

这里没有使用复杂的数据库,而是直接使用文本文件。

规定:

一个学生占一行 学生的不同信息之间使用 \t 分隔

例如:

学号 名字 性别 班级

这里的分隔符实际上是:

\t

也就是制表符。

这种格式非常简单,但是对于这个小项目已经够用了。


十二、实现保存函数

保存函数可以写成:

defsave():withopen('record.txt','w',encoding='utf-8')asf:forsinstudents:f.write(f"{s['studentId']}\t{s['name']}\t{s['gender']}\t{s['className']}\n")print(f'[存档成功] 共存储了{len(students)}条记录!')

核心逻辑就是:

打开文件 ↓ 遍历 students ↓ 把每个学生写成一行 ↓ 关闭文件

这里使用的是:

withopen(...)

所以不需要手动写close(),代码块结束之后文件会自动关闭。


十三、什么时候保存数据?

在学生信息发生变化的时候,就应该重新存档。

也就是:

新增学生 ↓ save() 删除学生 ↓ save()

这样程序的内存数据和文件中的数据就能保持更新。


十四、重新启动程序,还需要把数据读回来

光有save()还不够。

程序重新启动之后:

students=[]

还是一个空列表。

所以启动的时候,需要调用load(),把文件中的数据重新恢复到students中。


十五、读取存档文件

读取数据时先判断文件存不存在:

ifnotos.path.exists('record.txt'):return

如果文件不存在,就跳过读档。

如果存在,就:

students=[]

先准备一个空的学生列表。

然后打开文件:

withopen('record.txt','r',encoding='utf-8')asf:

接下来逐行读取:

forlineinf:

十六、把一行数据重新拆成学生信息

存档的时候,我们把数据用:

\t

隔开。

读档时就反过来,把这一行重新拆开:

line=line.strip()tokens=line.split('\t')

如果拆出来的数据数量不足:

iflen(tokens)!=4:print(f'当前行格式存在问题! line={line}')continue

就说明这行数据格式有问题,直接跳过。

正常情况下:

tokens[0] → 学号 tokens[1] → 姓名 tokens[2] → 性别 tokens[3] → 班级

然后重新构造字典:

student={'studentId':tokens[0],'name':tokens[1],'gender':tokens[2],'className':tokens[3]}

再:

students.append(student)

这样文件中的学生信息就重新恢复到内存中了。


十七、整个数据流程

把存档和读档放在一起看,整个过程其实非常清晰。

程序运行:

record.txt ↓ load() ↓ students ↓ 增 / 删 / 查 / 显示 ↓ save() ↓ record.txt

也就是说:

文件 ↔ 程序内存

之间形成了一个简单的数据同步过程。


十八、为什么这里使用“列表 + 字典”?

这个数据结构其实非常适合这个项目。

整体:

students=[]

学生列表里面保存:

student={'studentId':...,'name':...,'gender':...,'className':...}

所以整体结构就是:

students │ ├── student │ ├── studentId │ ├── name │ ├── gender │ └── className │ ├── student │ ├── studentId │ ├── name │ ├── gender │ └── className │ └── ...

列表解决“多个学生”的问题。

字典解决“一个学生有多个属性”的问题。

两者组合起来,刚好满足需求。


十九、完整代码+把程序打包成exe

# 实现一个命令行版本的学生管理系统importsysimportos.path# 使用这个全局变量, 来管理所有的学生信息# 这个列表的每个元素都是一个 "字典", 每个字典就分别表示了一个同学students=[]defsave():""" 用于存档 """withopen('record.txt','w',encoding='utf-8')asf:forsinstudents:f.write(f"{s['studentId']}\t{s['name']}\t{s['gender']}\t{s['className']}\n")print(f'[存档成功] 共存储了{len(students)}条记录!')defload():""" 用于读档 """# 如果存档文件不存在, 则直接跳过读档流程# 为了避免读方式打开文件的时候, 文件不存在引起异常ifnotos.path.exists('record.txt'):returnglobalstudents students=[]withopen('record.txt','r',encoding='utf-8')asf:forlineinf:line=line.strip()tokens=line.split('\t')iflen(tokens)!=4:print(f'当前行格式存在问题! line={line}')continuestudent={'studentId':tokens[0],'name':tokens[1],'gender':tokens[2],'className':tokens[3]}students.append(student)print(f'[读档成功] 共读取了{len(students)}条记录')defmenu():print(' 1. 新增学生')print(' 2. 显示学生')print(' 3. 查找学生')print(' 4. 删除学生')print(' 0. 退出程序')choice=input(' 请输入您的选择: ')returnchoicedefinsert():print('[新增学生] 开始!')studentId=input('请输入学生的学号: ')name=input('请输入学生的姓名: ')gender=input('请输入学生的性别: ')ifgendernotin('男','女'):print('性别输入的内容不符合要求, 新增失败!')returnclassName=input('请输入学生的班级: ')student={'studentId':studentId,'name':name,'gender':gender,'className':className}globalstudents students.append(student)save()print('[新增学生] 完毕!')defshow():print('[显示学生] 开始!')forsinstudents:print(f"[{s['studentId']}]\t{s['name']}\t{s['gender']}\t{s['className']}")print(f'[显示学生] 完毕! 共显示了{len(students)}条数据!')deffind():# 根据学生姓名, 来进行查找print('[查找学生] 开始!')name=input('请输入要查找的同学姓名: ')count=0forsinstudents:ifname==s['name']:print(f"[{s['studentId']}]\t{s['name']}\t{s['gender']}\t{s['className']}")count+=1print(f'[查找学生] 结束! 共找到了{count}个匹配的同学!')defdelete():print('[删除学生] 开始!')studentId=input('请输入要删除的学生学号: ')forsinstudents:ifstudentId==s['studentId']:print(f"删除{s['name']}同学的信息!")students.remove(s)save()print('[删除学生] 结束!')defmain():""" 入口函数 """# 通过控制台和用户进行交互print('----------------------------------------------')print(' 欢迎来到学生管理系统 ')print('----------------------------------------------')load()whileTrue:# 通过 menu 函数来打印出菜单项choice=menu()ifchoice=='1':# 新增学生insert()elifchoice=='2':# 显示学生show()elifchoice=='3':# 查找学生find()elifchoice=='4':# 删除学生delete()elifchoice=='0':# 退出程序print('goodbye!')sys.exit(0)else:print('您的输入有误! 请重新输入!')continuemain()

目前程序是一个:

.py

文件。

这种文件需要目标机器安装 Python 环境才能运行。

为了方便部署,可以使用:

PyInstaller

把 Python 程序打包成.exe。

首先安装:

pipinstallpyinstaller

然后进行打包。

其中-F表示打包成单个 exe。

打包完成之后,就可以把生成的程序复制到其他机器上使用,而不需要再单独安装 Python 环境。


二十、这个项目把哪些知识串起来了?

回头看一下这个学生管理系统,里面其实已经用到了不少 Python 基础知识。

函数 ↓ main / menu / insert / show / find / delete 列表 ↓ students 字典 ↓ student 条件语句 ↓ 菜单判断、数据合法性判断 循环 ↓ 菜单循环、遍历学生 文件 ↓ save / load 字符串 ↓ \t 分隔、split、strip 模块 ↓ sys、os 程序部署 ↓ PyInstaller

所以这个项目虽然只是一个命令行学生管理系统,但是已经不是单独练习某一个语法了,而是开始尝试把多个知识点组合到一个完整程序中。


二十一、总结

这个学生管理系统最核心的地方,我觉得不是“增删查”本身,而是慢慢理解一个程序应该怎么组织。

比如:

main()

负责整个程序的流程。

menu()

负责菜单。

insert() show() find() delete()

分别负责具体的数据操作。

save() load()

负责数据持久化。

这样每个函数各干各的事情,整个程序看起来就不会乱。项目的基本结构也正是围绕这些函数展开的。

如果只是在main()里面把所有代码全部写完,刚开始可能还能看懂,但功能一多,很快就会变得非常混乱。

所以我觉得这个项目真正值得记录的一点就是:

当程序开始变复杂之后,不能只想着“把功能写出来”,还要开始考虑怎么把代码组织起来。

从一个简单的.py文件,到能够完成增删查、保存数据、重新加载数据,最后再打包成 exe,这基本就是一次比较完整的 Python 小项目实践。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询