关于明星投票系统的作业分享
按要求完成明星投票系统的相关功能.
功能需求: 1. 用户注册. 将用户名和密码保存在文件中.
2. 登录功能. 不需要三次登录. 正常反复无限登录就可以. 直到登录成功为止
3. 用户登录后可以查看所有明星信息. 明星信息保存在明星文件中.
4. 给明星进行投票
5. 每个人每24小时只能投一次票(扩展功能, 装饰器)
首先说下自己的情况,从一开始想先画流程图再去写代码,但是经过半天的不懈努力,我终于放弃这个想法(也不知道是自己太挑了还是不熟悉画图工具最终也没画出什么有价值的,总之对画图的效率,工具都不满意)。然后就开始按照给出的需求写,首先想到有四个主要的函数:注册,登录,显示明星信息,给明星投票。注册和登录没有做优化和扩展很简单就完成了,显示明星信息也很简单就是读取文件,然后给明星投票也是文件操作之修改文件。四个主要功能的函数完事了就开始琢磨函数间的联系及扩展逻辑:
1.注册是需要判断用户名重复(没有难度的)及重复后的相关操作
2.注册成功后是否去登录的操作(日常操作)
3.登录状态问题(字典及装饰器)用来控制显示明星信息及给明星投票
4.登录成功后直接跳转到投票页面(理论上应该是到另一个主菜单只有查看明星、投票及退出)
5.本题升级的难点(用日志记录每次操作投票的时间,其中涉及时间的转换,耗时最多)
6.最后加一个main方法把所有逻辑及方法串起来。
总结下:在目前编程基础不扎实及经验很渣的时候,应该将整体需求化繁为简(彦涛老师课上讲过),将大致功能完善了再开始打磨每个单体的需求及每个个体需求间的联系。
下面是一段花了不知多久(因为老走神,貌似间断的有6小时左右)写出来的垃圾代码(就是完成了需求,其中有很多可以改进的地方),不嫌弃的可以看俩眼。
1 import os 2 import time, datetime 3 from functools import wraps 4 5 6 def register(): 7 ''' 8 用来注册,好像是句废话 9 :return: 10 ''' 11 flag = True 12 while flag: # 如果重复继续输入要注册的用户名 13 user = input('请输入用户名:') 14 with open('userinfo', 'r', encoding='utf-8')as f1: 15 for i in f1: 16 if user == i.split(',')[0]: # 判断用户名是否重复 17 print('用户名重复,请重新输入!') 18 break 19 else: 20 flag = False 21 22 pwd = input('请输入密码:') 23 with open('userinfo', 'a', encoding='utf-8')as f2: # 将用户名及密码写入用户信息中 24 f2.write(user + ',' + pwd + '\n') # 最后加个换行符可以保证每个用户为一行的数据规范 25 print(f'注册成功,您的用户名是{user},密码是{pwd}') 26 user_choose = input('是否去登录?(y/Y继续,其他任意键退出程序)') 27 if user_choose.upper() == 'Y': 28 login() 29 else: 30 exit() 31 32 33 # register() 34 dic = {'user': None, 'status': None} # 存储登录状态 35 36 37 def wrapper_login(fn): 38 ''' 39 用来验证是否已经登录 40 :param fn: 被装饰的方法 41 :return: inner 42 ''' 43 44 def inner(*args, **kwargs): 45 ''' 46 装饰器的真正执行者 47 :param args: 48 :param kwargs: 49 :return: fn函数执行的结果 50 ''' 51 if dic['status'] == True: # 用来验证是否登录成功 52 ret = fn(*args, **kwargs) 53 return ret 54 else: 55 print('对不起,您还没有登录!') 56 login() 57 58 return inner 59 60 61 def login(): 62 ''' 63 登录函数 64 :return: 65 ''' 66 while True: 67 username = input('账号:') 68 password = input('密码:') 69 with open('userinfo', 'r', encoding='utf-8')as f: 70 for i in f: 71 user_file, pwd_file = i.strip().split(',') 72 if username == user_file and password == pwd_file: 73 print(f'恭喜{username}登录成功!') 74 dic['user'] = username 75 dic['status'] = True 76 vote_star() 77 return 78 else: 79 print('用户名或者密码错误请重新输入!') 80 81 82 # login() 83 @wrapper_login 84 def show_star_info(): 85 ''' 86 用来显示明星信息 87 :return: 88 ''' 89 with open('star_info', 'r', encoding='utf-8')as f: 90 for i in f: 91 print(i.strip()) 92 93 94 # show_star_info('star_info') 95 def wrapper_time(fn): 96 ''' 97 用来记录访问日志 98 :param fn: 被装饰的方法 99 :return: inner 100 ''' 101 102 @wraps(fn) 103 def inner(*args, **kwargs): 104 ''' 105 装饰器的执行者 106 :param args: 107 :param kwargs: 108 :return: fn执行的结果 109 ''' 110 with open('log', 'r', encoding='utf-8')as f2: 111 data = f2.readlines() # 将数据读取到列表中 112 str_time_last = data[-1].strip().split('|')[1] # 用切片找到最后一列的时间 113 time_last = time.mktime(time.strptime(str_time_last, "%Y-%m-%d %X")) # 将最后一次投票的时间戳 114 time_start = time.time() 115 time_difference = time_start - time_last # 计算时间差 116 if time_difference >= 60: # 判断时间差 117 ret = fn(*args, **kwargs) 118 str_time_end = time.strftime("%Y-%m-%d %X") 119 with open('log', 'a', encoding='utf-8')as f1: 120 f1.write('在|%s|访问了|%s\n' % (str_time_end, fn.__name__)) 121 return ret 122 else: 123 print('距离上次投票时间不足1分钟,无法进行下次投票!') 124 125 return inner 126 127 128 @wrapper_login 129 @wrapper_time 130 def vote_star(): 131 ''' 132 用于给明星投票 133 :return: 134 ''' 135 show_star_info() 136 user_id = input('请选择您要投票的明星编号:') 137 with open('star_info', 'r', encoding='utf-8')as f1, \ 138 open('new_star_info', 'w', encoding='utf-8')as f2: 139 for i in f1: 140 file_id, file_name, file_poll = i.strip().split('|') 141 if str(user_id) == file_id: 142 file_poll = str(int(file_poll) + 1) 143 f2.write('%s|%s|%s\n' % (file_id, file_name, file_poll)) 144 os.remove('star_info') 145 os.rename('new_star_info', 'star_info') 146 show_star_info() 147 print('稍事休息,1分钟后才可以继续投票!') 148 149 150 def main(): 151 ''' 152 系统整个的执行逻辑 153 :return: 154 ''' 155 global register, login, show_star_info, vote_star # 将函数中需要调用的方法全部引用为全局变量 156 register, login, show_star_info, vote_star = register, login, show_star_info, vote_star # 将同名的变量赋值成原来的方法 157 print('欢迎进入明细投票系统:') 158 tu_menu = ('注册', '登录', '查看明星', '明星投票', '退出系统') 159 tu_def = (register, login, show_star_info, vote_star) 160 for index, element in enumerate(tu_menu): 161 print(f'{index+1}.{element}') 162 choose = int(input('请选择您要进行的操作:')) 163 for index, element in enumerate(tu_def): # 此处用循环代替大幅的if语句 164 if choose == index + 1: 165 element() 166 break 167 elif choose == 5: 168 exit() 169 else: 170 print('输入有误,请重新输入!') 171 172 173 # vote_star('star_info',3) 174 if __name__ == '__main__': 175 main()
一段没有优化的代码
对于单个用户登录后时间的计算问题重新优化部分:
1 def wrapper_time(fn): 2 ''' 3 用来记录访问日志 4 :param fn: 被装饰的方法 5 :return: inner 6 ''' 7 8 @wraps(fn) 9 def inner(*args, **kwargs): 10 ''' 11 装饰器的执行者 12 :param args: 13 :param kwargs: 14 :return: fn执行的结果 15 ''' 16 with open('log', 'r', encoding='utf-8')as f2: 17 # data = f2.readlines() # 将数据读取到列表中 18 # str_time_last = data[-1].strip().split('|')[2] # 用切片找到最后一列的时间 19 # time_last = time.mktime(time.strptime(str_time_last, "%Y-%m-%d %H:%M:%S")) # 将最后一次投票的字符串时间转化成时间戳 20 lst = [] # 空列表用来放单个用户的访问时间戳 21 for i in f2: 22 username, str_time_last = i.strip().split('|')[0], i.strip().split('|')[2] # 拿到俩个关键字段,名字和字符串的时间 23 if username == dic['user']: # 如果日志里的用户名和登录的用户相同,就进行把时间都拿出来 24 stamp_time_last = time.mktime(time.strptime(str_time_last, "%Y-%m-%d %H:%M:%S")) # 和之前一样转换下字符串的时间变为时间戳 26 lst.append(stamp_time_last) # 添加到列表里 27 else: # 如果日志里还没有该用户名那就直接访问,并记录日志 28 ret = fn(*args, **kwargs) 29 str_time_end = time.strftime("%Y-%m-%d %H:%M:%S") # 获取当前的字符串时间 30 with open('log', 'a', encoding='utf-8')as f1: 31 f1.write('%s|在|%s|访问了|%s\n' % ( 32 dic['user'], str_time_end, fn.__name__)) # 日志记录 chang|在|2018-06-19 19:34:09|访问了|vote_star 33 return ret 34 time_last = max(lst) # 取到列表中最大的时间戳为最后一次的投票时间 35 time_start = time.time() # 访问函数前的时间戳 36 time_difference = time_start - time_last # 计算时间差 37 if time_difference >= 60: # 判断时间差 38 ret = fn(*args, **kwargs) 39 str_time_end = time.strftime("%Y-%m-%d %H:%M:%S") 40 with open('log', 'a', encoding='utf-8')as f1: 41 f1.write('%s|在|%s|访问了|%s\n' % (dic['user'], str_time_end, fn.__name__)) 42 return ret 43 else: 44 print('距离上次投票时间不足1分钟,无法进行下次投票!') 45 46 return inner
前面的时间功能搞定的话这个想想就明白了!只修改了时间装饰器部分,代码还是很渣
网址:关于明星投票系统的作业分享 https://mxgxt.com/news/view/115536
相关内容
2019 LPL全明星投票地址如何用数据中台,做一套关于明星的舆情分析系统?
2021明星势力榜投票 附最新榜单+投票入口
2020明星权力榜投票入口、最新榜单排名
2020百度男明星人气榜投票榜单、投票入口一览
明星升级系统
娱乐女明星排行榜投票
LOL2018全明星投票 粉丝们为了拉票开撕了
流量明星的行业分析
明星权力榜年度最受欢迎华语男演员投票(投票入口+最新榜单)