关于明星投票系统的作业分享

按要求完成明星投票系统的相关功能.  

 功能需求: 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 + '
')  # 最后加个换行符可以保证每个用户为一行的数据规范
 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
' % (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
' % (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
' % (
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
' % (dic['user'], str_time_end, fn.__name__))
42             return ret
43         else:
44             print('距离上次投票时间不足1分钟,无法进行下次投票!')
45 
46     return inner
前面的时间功能搞定的话这个想想就明白了!只修改了时间装饰器部分,代码还是很渣
原文地址:https://www.cnblogs.com/changwentao/p/9193468.html