鱼C论坛

 找回密码
 立即注册
查看: 5931|回复: 222

[技术交流] 【详解】python信息管理系统【新】

  [复制链接]
发表于 2020-9-19 16:32:28 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 昨非 于 2020-10-14 18:33 编辑

【详解】python信息管理系统


一、前言
    花了整整一天时间搞了个python的信息管理系统,完成一大半了突然发现,鱼c已经有@zltzlt大佬做过了,而且功能十分齐全(比我做的好),一时间有点儿懊恼,大家能理解这种心理就好...
    毕竟鱼c只有三种帖子最火,第一种——官方教程等,这个理所当然,没啥意见;第二种——pygame小游戏诸如此类,毕竟原版教程就是冲着这个去的,忍了;第三种——爬取妹子图,花样爬取妹子图,爬取花样妹子图......,我:????
    转念一想,作为后来者,目前我们所做的东西绝大多数都是前人做过的,这本就是一种“前人栽树,后人乘凉”的体现。代码上,我承认以我入门不久的水平是不可能做到超越,不过我可以把整个程序描述的更详细点儿。
  我承认做不到100%的原创,也感谢前人给的参考,具体内容如下,帖子的顺序基本上算是还原了整个程序的制作过程了。

注:
本篇只是简单完成了信息管理系统的基本增删改查功能并注以解释,其余功能未完成或尚待优化之处,今后笔者会尽力更新的,还望读者见谅。
初次运行,请将【数据存储】部分students列表定义代码解除注释并将下方两行读取文件注释掉,避免因json文件不存在而报错。这一不足笔者后续会改善的,见谅

(完成不易,求大家评分支持!!)



二、代码及详解

1、信息管理系统框架

首先要完成的是打印出一个交互界面(相信大家学c过语言的都有经验),本质上就是一个菜单+死循环,在死循环中,通过input()函数满足交互需要,并依照菜单所示,完成分支的框架搭建,这部分没什么难度,附上代码和效果图:

  1. #打印菜单,提示如何操作:
  2. def menu():
  3.     #菜单以多行字符串打印
  4.     str_menu = """
  5. \t欢迎使用【学生信息管理系统】
  6. ********************************************
  7. 请输入您想要进行的操作:
  8. 1.添加指定信息
  9. 2.显示全部信息
  10. 3.查询指定信息
  11. 4.删除指定信息
  12. 5.修改指定信息
  13. 6.打印操作提示

  14. 0.退出系统
  15. ********************************************
  16. """
  17.     print(str_menu)

  18. menu()

  19. #主体循环
  20. while True:
  21.     #输入操作:
  22.     action = input("请输入您想要进行的操作:")
  23.    
  24.     #分支判断
  25.     #1.添加指定信息
  26.     if action == "1":
  27.         print("【添加指定信息】")
  28.         pass
  29.    
  30.    
  31.     #2.显示全部信息
  32.     elif action == "2":
  33.        print("【显示全部信息】")
  34.        pass
  35.    
  36.     #3.查询指定信息
  37.     elif action == "3":
  38.        print("【查询指定信息】")
  39.        pass
  40.    
  41.     #4.删除指定信息
  42.     elif action == "4":
  43.        print("【删除指定信息】")
  44.        pass
  45.    
  46.     #5.修改指定信息
  47.     elif action == "5":
  48.        print("【修改指定信息】")
  49.        pass
  50.    
  51.     #6.打印操作提示
  52.     elif action == "6":
  53.        print("【打印操作提示】")
  54.        pass
  55.    
  56.     #0.退出系统
  57.     elif action == "0":
  58.         print("退出【信息管理系统】,欢迎下次使用!")
  59.         break
  60.     #输入错误:
  61.     else:
  62.         print("输入操作不存在,请按提示正确输入!")
复制代码



                               
登录/注册后可看大图



2、选择数据存储方式

  我们知道,数据可以保存在内存中,也可以保存在本地。
  在内存中保存的数据,只在程序执行过程中存在,具有一些局限性,因此我们更提倡另一种方式——以文件形式保存在本地。
  可选的文件格式有很多种,诸如:txt,csv, xml,json,html 以及小甲鱼讲过的pkl, 这里我选择数据格式为json,想用pkl的可以参考https://fishc.com.cn/thread-144923-1-1.html
  针对信息管理系统:多个学员,以列表存储;每个学员,以字典保存各属性及数据;故:列表包含字典来存储。
样例数据为:

  1. students = [
  2.         {'name':'李四','chinese':'64','math':'65','English':'66','total':195},
  3.         {'name':'王五','chinese':'65','math':'65','English':'66','total':196},
  4.         {'name':'赵六','chinese':'66','math':'65','English':'66','total':197}
  5.         ]
复制代码



3、功能实现-打印

   有了数据,我们从简单的开始,先实现【全部数据打印】:
   即:遍历列表打印字典的值:



                               
登录/注册后可看大图



以*解包,(加入分隔符)效果如下:


                               
登录/注册后可看大图


这部分的代码如下:

  1. #显示全部信息
  2. def print_info():
  3.     print('姓名    语文    数学    英语    总分')
  4.     for student in students:
  5.         print(*student.values(),sep="     ")
复制代码



4、功能实现-插入

  我们知道,每个学员的信息以字典的形式储存在列表students中,所以插入分为两步;
【收集信息】->【添加到students列表】
收集信息时应注意,input函数返回的为字符串类型,所以作为成绩相加应该转为int

代码及效果图如下:

  1. #添加指定信息
  2. def insert():
  3.     #收集(输入)信息
  4.     name = input('请输入学生姓名:')
  5.     chinese = int(input('请输入学生语文成绩:'))
  6.     math = int(input('请输入学生数学成绩:'))
  7.     English = int(input('请输入学生英语成绩:'))
  8.     total = chinese + math + English
  9.    
  10.     #添加到students列表中
  11.     students.append(
  12.              {'name':name,'chinese':chinese,'math':math,'English':English,'total':total}
  13.             )
复制代码



                               
登录/注册后可看大图



5、功能实现-查找

查找的本质是从students列表里面查找,但实际的操作对象确实内部的字典。
因此,需要将列表数据一个个取出来(遍历),然后对比字典name项。
存在一个问题,在找不到的情况下能直接搭配if使用else吗?

错误代码:


  1. def search():
  2.     name = input('请输入需查询学生姓名:')
  3.    
  4.     for student in students: #遍历列表
  5.         if name == student['name']: #对比字典的name
  6.             print('姓名    语文    数学    英语    总分')
  7.             print(*student.values(),sep="     ")
  8.          
  9.         else:
  10.             print("该学生不存在!")
复制代码


产生的效果如下:



                               
登录/注册后可看大图


【解决方案】:else与for搭配使用,在执行完for后会执行else
众鱼友:好像还是不对啊?
当然,需要在if判断查找到后加一个break,跳出for循环,之后的else自然就不会再执行了。反之,当没有查找到时,自然就不会执行break,else照常打印。

正确代码:


  1. def search():
  2.     name = input('请输入需查询学生姓名:')
  3.    
  4.     for student in students: #遍历列表
  5.         if name == student['name']: #对比字典的name
  6.             print('姓名    语文    数学    英语    总分')
  7.             print(*student.values(),sep="     ")
  8.             break
  9.     else:
  10.         print("该学生不存在!")
复制代码


效果图:


                               
登录/注册后可看大图




5、功能实现-删除和修改

自不必多说,苍老师说过:“能找到,就能为所欲为”
你会发现这部分和查找何其相似(搬砖暴露了)。
代码如下:


  1. #删除指定信息√
  2. def delete_info():
  3.     name = input('请输入需删除的学生姓名:')
  4.    
  5.     for student in students: #遍历列表
  6.         if name == student['name']: #对比字典的name
  7.             students.remove(student)
  8.             break
  9.     else:
  10.         print("该学生不存在!")

  11. #修改指定信息√
  12. def modify_info():
  13.     name = input('请输入需修改的学生姓名:')
  14.    
  15.     for student in students: #遍历列表
  16.         if name == student['name']: #对比字典的name
  17.             student['name']= input('请输入更新后学生姓名:')
  18.             student['chinese'] = int(input('请输入更新后学生语文成绩:'))
  19.             student['math']  = int(input('请输入更新后学生数学成绩:'))
  20.             student['English'] = int(input('请输入更新后学生英语成绩:'))
  21.             student['total']  = student['chinese'] +student['math'] + student['English']
  22.             break
  23.     else:
  24.         print("该学生不存在!")
复制代码


效果图如下:



                               
登录/注册后可看大图



                               
登录/注册后可看大图



6、功能实现-保存与后期读取

本程序默认退出程序时自动将内存中的students列表以json格式保存到本地。代码位于最后部分以with语句嵌入:

  1. #0.退出系统(自动保存到本地json形式)
  2.     elif action == "0":
  3.         print("退出【学生信息管理系统】")
  4.         print("欢迎下次使用!")
  5.         with open("data.json",mode='w',encoding="utf-8") as f:
  6.              #将对象写入文件而不改变格式
  7.             #f.write(json.dumps(students)) #这样写json格式中文会是“乱码”
  8.             f.write(json.dumps(students,ensure_ascii=False))
  9.         break
复制代码




所谓“乱码”即为json格式里中文的sacii码,在dumps方法中加入ensure_ascii=False参数即可正确显示中文内容。
json格式中文“乱码”及修正后效果图:



                               
登录/注册后可看大图
         

                               
登录/注册后可看大图




后期读取代码在【数据存储】部分,这部分可与初始化时students列表相互替代:
  1. with open("data.json",mode='r',encoding="utf-8") as f:
  2.     students = json.loads(f.read()) #注:read读取出来的时字符串,需要转为json对象
复制代码




三、全部代码

游客,如果您要查看本帖隐藏内容请回复



四、更新部分


1、更新内容概述:

(1)、数据存储部分,排除初次运行时json文件不存在需要手动修改代码的不便
(2)、部分注释内容不准确
(3)、数据结构中加入唯一ID解决按名字查找的重名问题
(4)、添加(多标准)排序功能  




2、具体内容


关于问题一,笔者通过加入打开文件的异常处理解决,这样即保留了必要的初始数据,也不会影响到后续读取文件已有内容。
代码如下:


  1. try:
  2.     with open("data.json",mode='r',encoding="utf-8") as f:
  3.         students = json.loads(f.read())
  4.         #注:read读取出来的时字符串,需要转为json对象

  5. except FileNotFoundError:
  6.     students = [  #初始数据,初次运行时避免文件打开报错
  7.         {'id':'20200001','name':'李四','chinese':'64','math':'65','English':'66','total':195},
  8.         {'id':'20200002','name':'王五','chinese':'65','math':'65','English':'66','total':196},
  9.         {'id':'20200003','name':'赵六','chinese':'66','math':'65','English':'66','total':197}
  10.         ]
复制代码



关于问题二、三,内容在此不作赘述,详情请参考下方更新后的代码,有不足或可改进之处,欢迎评论指出。


新增排序功能部分:

列表的sort方法可以实现将一个列表中元素按照升序排列。然后,sort方法还可以按照我们选定的标准进行元素排序。


  1. list.sort(key=None, reverse=False)
复制代码


key:匹配一个一元的函数或者表达式,按照这个值决定对应元素在列表中的位置。这里我们定义一个函数sort_key()来作为标准,并利用交互界面提供给用户选择标准的操作空间。
reverse: 一个布尔值,若是True,表示要逆序即从大到小,False表示顺序从小到大。
排序部分代码如下:



  1. #自定义排序(按各成绩)
  2. def sorted_by_grade():
  3.     sort_way = input(
  4.                 "请选择排序方式:\n"
  5.                 "1按语文成绩排序\n"
  6.                 "2按数学成绩排序\n"
  7.                 "3按英语成绩排序\n"
  8.                 "0按总成绩排序")
  9.     while sort_way not in ['0', '1', '2', '3']:
  10.         sort_way = input(
  11.                     "输入无效!请选择排序方式:\n"
  12.                     "1按语文成绩排序\n"
  13.                     "2按数学成绩排序\n"
  14.                     "3按英语成绩排序\n"
  15.                     "0按总成绩排序")
  16.     if sort_way == '0':
  17.         def sort_key(x):
  18.             return x['total']
  19.     elif sort_way == '1':
  20.         def sort_key(x):
  21.             return int(x['chinese'])
  22.     elif sort_way == '2':
  23.         def sort_key(x):
  24.             return int(x['math'])
  25.     else:
  26.         def sort_key(x):
  27.             return int(x['English'])
  28.     new_students = sorted(students, key=sort_key, reverse=True)
  29.     print(title) #打印
  30.     for student in new_students:
  31.         print(*student.values(),sep="\t")  
复制代码



排完序后,可以由用户选择是否保存到本地,代码如下:


  1.     #保存入文件
  2.     save_in = input("是否将默认学号顺序存入文件 (y/n)?")
  3.     while save_in not in ['y', 'n']:
  4.         save_in = input("输入无效!是否保存 (y/n)?")
  5.     if save_in == 'y':
  6.          f = open("data.json",mode='w',encoding="utf-8")      
  7.          f.write(json.dumps(new_students,ensure_ascii=False))
  8.          print('保存成功!')
  9.     else:
  10.         print('排序结果如上!')
  11.         print('如之后还有需要,请重新排序或选择存入文件!')
复制代码



但笔者在测试时却出现了问题,即:排序后结果正确打印,选择保存到本地后,在此调用print_info()函数发现,打印顺序仍为排序前的顺序。整体语法上没有报错,那么问题只会出现在逻辑上。

经反复检查,发现问题所在:
函数中排序后的new_students列表是区别于students列表的局部变量,而在打印函数中,打印的始终是students列表。
有鱼友可能会问,退出系统(自动保存)后再运行不就好了吗?
但是还是不对的:退出系统的自动保存students 会覆盖排序后的new_students的保存效果。

为此,笔者专门去查看了一下@zltzlt的代码(连接见上文),发现他的每个函数都是独立打开文件并关闭实现操作的,而笔者的初衷是将students列表作为自始至终的操作对象。

【解决办法】:在调用环节嵌入文件读取,对new_students列表刚刚保存进去的数据进行读取,并依旧使用students作为列表名称。

代码如下:


  1.     #7.恢复默认顺序(学号顺序)
  2.     elif action == "7":
  3.         print("【恢复默认学号顺序】")
  4.         sorted_by_id()#存入重新打开
  5.         with open("data.json",mode='r',encoding="utf-8") as f:
  6.             students = json.loads(f.read())
  7.         
  8.     #8.自定义排序(按各成绩)
  9.     elif action == "8":
  10.         print("【自定义排序(按各成绩)】")   
  11.         sorted_by_grade()#存入重新打开
  12.         with open("data.json",mode='r',encoding="utf-8") as f:
  13.             students = json.loads(f.read())
  14.         
复制代码



完成排序的效果图如下:
id默认排序:


                               
登录/注册后可看大图


成绩排序:

                               
登录/注册后可看大图



3、更新后全部代码


游客,如果您要查看本帖隐藏内容请回复


五、结语

   感谢众多鱼友提出的宝贵建议,根据这几天大家的提示,我把我能做出来的部分都做了,可能依旧微不足道。
至今还没有完成的内容:
一、加入图形化界面:这个笔者学的不到家,还做不出来,不过今后如果我学会了,可以考虑补上。
二、调整数据结构以优化运行速度:首先感谢您的宝贵意见,但是以笔者的水平,只能说暂时还考虑不到哪一步了,所以十分抱歉。

   这篇帖子从代码到排版花了好久才完成,首先是真正意义上体会了一遍小甲鱼作扩展阅读之类教程的不容易。和甲鱼哥的目的差不多,这篇内容主要面向新手,所以没有什么太过硬核的东西,之前有鱼友评论说有些内容描述不准确,希望理解下,谢谢。
   内容上,我已经尽力完善了整个信息管理系统的功能,我知道这类代码随便一搜就是一大堆,这也是我在篇头说看到已经有人发过了而感到有些负面情绪的原因。但我也可以肯定,我应该是这里面写的最详细的一批了。


比不过大佬的游戏、爬虫那么吸引眼球,但也求一波评分支持!
Best wishes to FishC !

评分

参与人数 15荣誉 +24 鱼币 +21 贡献 +13 收起 理由
nizitao + 5 + 5
柿子饼同学 + 3
亢一飞 + 1 + 1 + 1 鱼C有你更精彩^_^
不会起名字的我 + 2 感谢楼主无私奉献!
小伤口 + 1 + 1 感谢楼主无私奉献!
严凯 + 5 + 3 鱼C有你更精彩^_^
Nate_2020 + 1 + 1 鱼C有你更精彩^_^
weiter + 2 + 3
zltzlt + 2 + 3 + 3 支持楼主!
my少年时代 + 1 感谢楼主无私奉献!

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2020-9-23 11:46:47 | 显示全部楼层
已更新至2.0版本,跪求评分支持!

评分

参与人数 1荣誉 +1 鱼币 +1 收起 理由
开心小傻猪 + 1 + 1 用心,好评

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2020-9-19 16:35:37 | 显示全部楼层
@不二如是 @zltzlt 这个能申精吗(新人正儿八经发的第一帖,求通过)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-19 16:46:27 | 显示全部楼层
感谢分享!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2020-9-19 17:04:55 | 显示全部楼层

没事,欢迎评论领鱼币
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-19 17:26:50 | 显示全部楼层

回帖奖励 +3 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2020-9-19 17:33:43 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-19 18:13:56 | 显示全部楼层
支持支持
前几天入python,希望有一天我也能在python写出数据库
到时希望各位大佬多多回答我的提问
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2020-9-19 18:40:14 | 显示全部楼层
巴巴鲁 发表于 2020-9-19 18:13
支持支持
前几天入python,希望有一天我也能在python写出数据库
到时希望各位大佬多多回答我的提问{:10_2 ...

我水平有限,一起学吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-19 18:46:45 | 显示全部楼层

回帖奖励 +3 鱼币

支持
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-19 18:47:10 | 显示全部楼层

回帖奖励 +3 鱼币

感谢分享~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-19 21:20:30 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-20 08:29:20 | 显示全部楼层

回帖奖励 +3 鱼币

昨非 发表于 2020-9-19 16:35
@不二如是 @zltzlt 这个能申精吗(新人正儿八经发的第一帖,求通过)

嗯嗯,可以哦!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2020-9-20 08:40:28 From FishC Mobile | 显示全部楼层
不二如是 发表于 2020-9-20 08:29
嗯嗯,可以哦!!

谢谢肯定
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-20 08:53:22 | 显示全部楼层

回帖奖励 +3 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-20 08:57:03 From FishC Mobile | 显示全部楼层

回帖奖励 +3 鱼币

支持
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2020-9-20 08:57:32 From FishC Mobile | 显示全部楼层
hrp 发表于 2020-9-20 08:57
支持

谢谢肯定
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-20 09:17:57 | 显示全部楼层

回帖奖励 +3 鱼币

66
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-20 10:36:11 | 显示全部楼层
1
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2020-9-20 12:40:35 | 显示全部楼层

回帖奖励 +3 鱼币

本帖最后由 疾风怪盗 于 2020-9-20 12:42 编辑

写得不错啊。。。。。。
1、能不能加图形化界面。。。。。。。。
2、如果学生重名,怎么办?
3、复制了代码,运行报错
FileNotFoundError: [Errno 2] No such file or directory: 'data.json'
是否可以增加判断,如果没有这个文件就新建一个空的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2020-9-20 12:42:04 | 显示全部楼层
疾风怪盗 发表于 2020-9-20 12:40
写得不错啊。。。。。。
能不能加图形化界面。。。。。。。。
考虑一个问题,如果学生重名,怎 ...

可以加的,还有排序,查找依据也不唯一。。。。
能优化的地方多了去了,
。。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1

GMT+8, 2021-12-2 00:30

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表