老男孩Day4作业:员工信息表程序

作业要求

- 实现增删改查操作:
- 可进行模糊查询,语法至少支持下面3种:
select name,age from staff_table where age > 22
select from staff_table where dept = "IT"
select from staff_table where enroll_date like "2013"
- 查到的信息,打印后,最后面还要显示查到的条数
- 可创建新员工纪录,以phone做唯一键,staff_id需自增
- 可删除指定员工信息纪录,输入员工id,即可删除
- 可修改员工信息,语法如下:
UPDATE staff_table SET dept = "Market" WHERE where dept = "IT"
staff_id,name,age,phone,dept,enroll_date
1,Alex Li,22,13651054608,IT,2013-04-01
2,Jack Wang,30,13304320533,HR,2015-05-03
3,Rain Liu,25,1383235322,Sales,2016-04-22
4,Mack Cao,40,1356145343,HR,2009-03-01
- 注意:以上需求,要充分使用函数,请尽你的最大限度来减少重复代码


 1)编写思路

编写思路参考下面GitHub链接中的流程图

https://github.com/ChuixinZeng/PythonStudyCode/blob/master/PythonCode-OldBoy/Day4/作业/Day4_员工信息表程序_流程图.png

2)具体实现

  1 # -*- coding:utf-8 -*-
  2 
  3 # Author:Chuixin Zeng
  4 
  5 import os
  6 # 导入shutil模块,用于备份文件
  7 import shutil
  8 import time
  9 
 10 # 定义一个装饰器,用于备份员工信息表
 11 # 这个装饰器是在全部功能实现以后,额外添加的,实现不修改函数的内容,不修改函数的调用方式,对用户透明
 12 
 13 def staff_info(func_type):
 14     def backup(func):
 15         def re_name(*args,**kwargs):
 16             # 如果func_type传入的参数值不是search_type,但是当前的操作不是查询,而是修改、删除或添加
 17             # 这种情况下,代表文件有改动过,就需要对改动前的staff_info.txt文件先进行备份
 18             if func_type != 'search_type':
 19                 backup_time = time.strftime('%Y%m%d_%H%M%S')
 20                 shutil.copyfile('staff_info.txt','staff_info_%s.bak' % backup_time)
 21                 print("原始员工信息表已备份为 staff_info_%s.bak" % backup_time)
 22             print("已有员工信息如下:")
 23             # 备份完成之后,将当前员工信息表的内容打印出来
 24             with open('staff_info.txt','r',encoding='utf-8') as f:
 25                 for line in f:
 26                     line = line.strip().split(',')
 27                     print('|'+'|'.join(line)+'|')
 28 
 29             # 上面备份完了之后,下面res的内容是执行被装饰的函数,然后再执行文件重命名
 30             # 后面加的*args **kwargs表示函数有参数就传进来,没参数就是空,比较灵活
 31             res = func(*args,**kwargs) # 这一句的func实际上是被装饰的函数
 32 
 33             # 如果func_type传入的值是mod_type或者del_type,代表是修改或删除了文件,这个时候做下面的操作:
 34                 # 1. 因为原始的staff_info.txt文件已经备份过,所以这时候可以把原始文件删除掉了
 35                 # 2. 将函数中新生成的staff_info_new文件改名为staff_info.txt,代表最终删除或修改完成
 36             if func_type in ['mod_type','del_type'] and os.path.exists('staff_info_new'):
 37                 os.remove('staff_info.txt')
 38                 os.rename('staff_info_new','staff_info.txt')
 39             return res # 返回res的内存地址
 40         return re_name # 返回re_name的内存地址,实际上该函数包含重命名和备份文件
 41     return backup
 42 
 43 # 定义查询函数,用于从员工信息表中查询信息
 44 @staff_info(func_type='search_type')
 45 def search():
 46     user_search = input("请输入模糊查询的语句:").strip()
 47     # select name,age from staff_table where age > 22
 48     # select * from staff_info where dept = "IT"
 49     # select * from staff_info where enroll_date like "2013"
 50     # 将输入的条件语法以空格形式拆分成列表
 51     search_list = user_search.split(' ')
 52     #print(search_list)
 53     # 定义一个列表,用于保存查询结果
 54     found_info = []
 55     with open('staff_info.txt','r',encoding='utf-8') as f:
 56         for line in f:
 57             user_info = line.strip().split(',') # 循环读取员工信息
 58             # print(user_info)
 59             # ['staff_id', 'name', 'age', 'phone', 'dept', 'enroll_date']
 60             # ['1', '张三', '25', '152015410', '运维', '2013-11-01']
 61 
 62             # 将查询条件字符串写入变量,这里的查询条件对应的是age > 22
 63             conditional = '%s %s %s' % (user_info[2],search_list[6],search_list[7])
 64             # print(conditional) # age > 22
 65 
 66             # 如果用户输入的查询表达式里面第六个元素是=,则替换成==
 67             # 因为查询条件有可能是:select name,age from staff_table where age = 25
 68             # 为了方便if判断,就需要把=替换成==
 69             if search_list[6] == '=': # 如果是等号就替换
 70                 conditional = conditional.replace('=','==')
 71 
 72             # 用语句关键字匹配,用eval()将字符串转换为判断条件
 73             # 如果用户输入的查询表达式符合下面的条件
 74             if search_list[5] == 'age' and user_info[0].isdigit() and eval(conditional):
 75                 # 则把用户信息表的name,age元素附加到存放查询结果的表格中
 76                 found_info.append([user_info[1],user_info[2]])
 77 
 78             # 如果用户输入的查询表达式符合下面的条件
 79             # 查询语句里面包含元素dept,并且用户信息表的dept信息和查询表达式的dept信息匹配
 80             elif search_list[5] == 'dept' and user_info[4] in search_list[7]:
 81                 # 则把user_info员工信息表的匹配行整个附加到found_info中
 82                 found_info.append(user_info)
 83             # 通过用户输入的表达式中的enroll_date和用户信息表进行匹配,如果匹配上,则附加行到found_info表
 84             # 切片出用户信息列表中的年份与语法中的年份对比,年份只保留年,例如2017,切片后,去掉月日信息-11-01
 85             elif search_list[5] == 'enroll_date' and user_info[5][0:4] in search_list[7]:
 86                 found_info.append(user_info)
 87         if not found_info:
 88             print("没有找到你要搜索的员工!
")
 89         else:
 90             print("找到如下员工信息:
")
 91             for i in found_info:
 92                 print('|'.join(i))
 93             print("
共计找到 %d 条信息
" % len(found_info))
 94     return found_info
 95 
 96 @staff_info(func_type='add_type')
 97 def add():
 98     user_add = input("请输入您要增加的员工信息(格式要求 zengchuixin,22,12378902792,IT,2014-06-23):").strip()
 99     add_list = user_add.split(",") # 用,号将用户输入的员工信息拆分为列表
100     # print(add_list) # ['guoguoguo', '22', '12378902792', 'IT']
101     phone = [] # 定义一个空列表
102     with open('staff_info.txt','r+',encoding="utf-8") as f:
103         user_id = 0 # 保存员工ID的变量,初始值0
104         for line in f:
105             user_info = line.strip().split(',')
106             # print(user_info)
107             # ['staff_id', 'name', 'age', 'phone', 'dept', 'enroll_date']
108             # ['1', '张三', '25', '152015410', '运维', '2013-11-01']
109 
110             # 把现有员工信息表中已经存在的phone的值追加保存到前面定义的phone列表里面
111             phone.append(user_info[3])
112 
113             # 判断是否要给员工ID变量赋值,循环结束后,user_id的值就是最后一行员工信息的ID值
114             if user_info[0].isdigit() and user_id < int(user_info[0]):
115                 user_id = int(user_info[0])
116 
117         # print(phone) # 打印查看追加后的phone列表,包含现有员工的phone信息
118         # 这里判断增加的信息是不是存在,是以phone做唯一键进行判断的,如果phone不存在,则认为是新员工
119         # 而且staff_id要自动增加,前面for循环里面的user_id保存了最后一行user_id的值
120         # 如果通过phone判断员工信息不存在,则ID在此基础上+1
121         if add_list[2] not in phone:
122             f.write('
'+str(user_id+1)+','+','.join(add_list))
123             print("员工%s的信息已添加成功!
" % add_list[0])
124         else:
125             print("您要添加的员工信息已经存在!
")
126 
127 @staff_info(func_type='mod_type')
128 def modify():
129     user_mod = input("请输入修改员工信息的语法:").strip()
130     # UPDATE staff_table SET dept = "Market" WHERE where dept = "IT"
131     mod_list = user_mod.split()
132     user_list = []
133     mod_flag = False
134     with open('staff_info.txt','r',encoding='utf-8') as f,
135         open('staff_info_new','w',encoding='utf-8') as f2:
136         for line in f:
137             user_info = line.strip().split(',')
138             # 如果用户的dept和修改用户信息语法的dept的值匹配(实际是元素10)
139             if user_info[4] in mod_list[10]:
140                 # 将标志位设置为true,如果不满足这个if的条件,则默认标志位为false
141                 mod_flag = True
142                 # 将修改语法中set的dept的值更新到user_info中的dept的值,即达到了修改dept的目的
143                 user_info[4] = mod_list[5].strip('"')
144                 print("员工%s 信息已修改!
" % user_info[1])
145             # 将修改过的员工信息表的所有内容附加到新的类别user_list
146             user_list.append(user_info)
147         # 从user_list列表里面循环读取每一行
148         # print(user_list) 结果是一个列表
149         for list in user_list:
150             # 如果list中的第一个元素不是数字,第一行肯定不是数字,是员工信息表的表头
151             if not list[0].isdigit():
152                 # 将list内容逐行写入到新的文件中
153                 f2.write(','.join(list))
154             else:
155                 # 如果是数字,则换行后,写入到新表,除了第一行,后续的行都是数字开头
156                 f2.write('
'+','.join(list))
157         if not mod_flag:
158             print("没有找到要修改信息的员工!
")
159 
160 @staff_info(func_type='del_type')
161 def delete():
162     user_del = input("请输入您要删除的员工的ID:").strip()
163     # 用户的ID必须是数字,如果用户输入的不是数字,则提示用户输入正确的ID
164     if not user_del.isdigit():
165         print("请输入正确的员工ID号:
")
166         return
167     else:
168         with open('staff_info.txt','r',encoding='utf-8') as f,
169             open('staff_info_new','w',encoding='utf-8') as f2:
170             # 逐行读取原始员工信息表中的内容
171             for line in f:
172                 user_info = line.strip().split(',')
173                 # 如果用户输入的数字和员工信息表元素0所在的数字匹配,则代表要删除的用户存在
174                 if user_del == user_info[0]:
175                     # 提示用户已删除员工,并打印出来已删除的员工信息
176                     print("已删除员工 %s" % line)
177                     continue
178                 # 如果不满足iF的条件,则把不满足的所有行写入到新的文件,满足的不写入,实现删除效果
179                 # 问题:永远只能删一行
180                 # 问题解决:通过前面定义的装饰器解决,如果有staff_info_new文件,则删除原始的staff_info文件,然后把new
181                 # 文件重命名为staff_info.txt即可
182                 else:
183                     if not line[0].isdigit():
184                         f2.write(line.strip())
185                     else:
186                         f2.write('
'+line.strip())
187 
188 # 定义查询界面
189 while True:
190     print("""1.模糊查询
191     2.创建新员工
192     3.修改员工信息
193     4.删除员工信息
194     5.退出
195     """)
196     menu_dict = {'1':search,'2':add,'3':modify,'4':delete}
197     user_chosen = input("请输入您想要操作的选项序号:")
198     if user_chosen in menu_dict.keys():
199         # 执行用户选择的函数
200         menu_dict[user_chosen]()
201     elif user_chosen == '5':
202         exit("下次再见!")
203     else:
204         print("请输入正确的格式!")

3)GitHub笔记

第四天的笔记地址:

https://github.com/ChuixinZeng/PythonStudyCode/tree/master/PythonCode-OldBoy/Day4/随堂练习

第四天的作业地址:

https://github.com/ChuixinZeng/PythonStudyCode/tree/master/PythonCode-OldBoy/Day4/作业

原文地址:https://www.cnblogs.com/ChuixinZeng/p/Jamie_Zeng_Day4.html