老男孩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("没有找到你要搜索的员工!\n") 89 else: 90 print("找到如下员工信息:\n") 91 for i in found_info: 92 print('|'.join(i)) 93 print("\n共计找到 %d 条信息\n" % 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('\n'+str(user_id+1)+','+','.join(add_list)) 123 print("员工%s的信息已添加成功!\n" % add_list[0]) 124 else: 125 print("您要添加的员工信息已经存在!\n") 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 信息已修改!\n" % 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('\n'+','.join(list)) 157 if not mod_flag: 158 print("没有找到要修改信息的员工!\n") 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号:\n") 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('\n'+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/作业