python 全栈开发,Day12(函数的有用信息,带参数的装饰器,多个装饰器装饰一个函数)
函数的执行时,*打散。
函数的定义时,*聚合。
from functools import wraps def wrapper(f): # f = func1 @wraps(f) def inner(*args,**kwargs): #聚合 #args (1,2,3) '''执行函数之前的相关操作''' ret = f(*args,**kwargs) # 打散 1,2,3 '''执行函数之后的相关操作''' return ret return inner @wrapper # func1 = wrapper(func1) func1 = inner def func1(*args): #args (1,2,3) 聚合 print(666) return args print(func1(*[1,2,3])) # inner(3,5) 打散
执行输出:
666
(1, 2, 3)
一、函数的有用信息
1.函数名 使用__name__方法获取
2.函数的解释 使用__doc___方法获取
举个例子
def func1(): """ 此函数是完成登陆的功能,参数分别是...作用。 :return: 返回值是登陆成功与否(True,False) """ print(666) # print(func1.__name__) # print(func1.__doc__) return True func1() print(func1.__name__) #获取函数名 print(func1.__doc__) #获取函数名注释说明
执行输出:
666
func1
此函数是完成登陆的功能,参数分别是...作用。
:return: 返回值是登陆成功与否(True,False)
这个有什么用呢?比如日志功能,需要打印出谁在什么时间,调用了什么函数,函数是干啥的,花费了多次时间,这个时候,就需要获取函数的有用信息了
带装饰器的函数
def wrapper(f): # f = func1 def inner(*args,**kwargs): #聚合 #args (1,2,3) '''执行函数之前的相关操作''' ret = f(*args,**kwargs) # 打散 1,2,3 '''执行函数之后的相关操作''' return ret return inner @wrapper def func1(): """ 此函数是完成登陆的功能,参数分别是...作用。 :return: 返回值是登陆成功与否(True,False) """ print(666) return True func1() print(func1.__name__) print(func1.__doc__)
执行输出:
666
inner
执行函数之前的相关操作
咦?为什么输出了inner,我要的是func1啊。因为函数装饰之后,相当于执行了inner函数,所以输出inner
为了解决这个问题,需要调用一个模块wraps
wraps将 被修饰的函数(wrapped) 的一些属性值赋值给 修饰器函数(wrapper) ,最终让属性的显示更符合我们的直觉
完整代码如下:
from functools import wraps def wrapper(f): # f = func1 @wraps(f) #f是被装饰的函数 def inner(*args,**kwargs): #聚合 #args (1,2,3) '''执行函数之前的相关操作''' ret = f(*args,**kwargs) # 打散 1,2,3 '''执行函数之后的相关操作''' return ret return inner @wrapper def func1(): """ 此函数是完成登陆的功能,参数分别是...作用。 :return: 返回值是登陆成功与否(True,False) """ print(666) return True func1() print(func1.__name__) print(func1.__doc__)
执行输出:
666
func1
此函数是完成登陆的功能,参数分别是...作用。
:return: 返回值是登陆成功与否(True,False)
二、带参数的装饰器
import time def timmer(*args,**kwargs): def wrapper(f): print(args, kwargs) #接收第1步的值 def inner(*args,**kwargs): if flag: start_time = time.time() ret = f(*args,**kwargs) time.sleep(0.3) end_time = time.time() print('此函数的执行效率%f' % (end_time-start_time)) else: ret = f(*args, **kwargs) return ret return inner return wrapper flag = True @timmer(flag,2,3) # 两步:1,timmer(flag,2,3) 相当于执行wrapper 2.@wrapper 装饰器 func1 = wrapper(func1) def func1(*args,**kwargs): return 666 print(func1())
执行输出:
(True, 2, 3) {}
此函数的执行效率0.300183
666
代码分析
import time #1.加载模块 def timmer(*args,**kwargs): #2.加载变量 5.接收参数True,2,3 def wrapper(f): #6.加载变量 8.f = func1 print(args, kwargs) #9.接收timmer函数的值True,2,3 def inner(*args,**kwargs): #10.加载变量. 13.执行函数inner if flag: #14 flag = True start_time = time.time() #15 获取当前时间 ret = f(*args,**kwargs) #16 执行func1 time.sleep(0.3) #19 等待0.3秒 end_time = time.time() #20 获取当前时间 print('此函数的执行效率%f' % (end_time-start_time)) #21 打印差值 else: ret = f(*args, **kwargs) return ret #22 返回给函数调用者func1() return inner #11 返回给函数调用者wrapper return wrapper #7.返回给函数调用timmer(flag,2,3) flag = True #3 加载变量 @timmer(flag,2,3) # 4.执行函数timmer(flag,2,3) 17.执行函数func1 两步:1,timmer(flag,2,3) 相当于执行wrapper 2.@wrapper 装饰器 func1 = wrapper(func1) def func1(*args,**kwargs): return 666 #18 返回给函数调用者f(*args,**kwargs) print(func1()) #12 执行函数
假定现在有100个函数,都加上了装饰器,增加了显示函数执行时间的功能,现在需要去掉!
怎能办?一行行代码去删除吗?太low了。
这个时候,直接在装饰器函数加一个参数即可。
import time flag = True def wrapper(f): def inner(*args,**kwargs): if flag: start_time = time.time() ret = f(*args,**kwargs) time.sleep(0.3) end_time = time.time() print('此函数的执行效率%f' % (end_time-start_time)) else: ret = f(*args, **kwargs) return ret return inner @wrapper def func1(*args,**kwargs): print(args,kwargs) return 666 print(func1())
执行输出:
此函数的执行效率0.300431
666
现在需要关闭显示执行时间
直接将flag改成false
import time flag = False def wrapper(f): def inner(*args,**kwargs): if flag: start_time = time.time() ret = f(*args,**kwargs) time.sleep(0.3) end_time = time.time() print('此函数的执行效率%f' % (end_time-start_time)) else: ret = f(*args, **kwargs) return ret return inner @wrapper def func1(*args,**kwargs): print(args,kwargs) return 666 print(func1())
执行输出:
() {}
666
这样,所有调用的地方,就全部关闭了,非常方便
写装饰器,一般嵌套3层就可以了
a = 5 def func1(): a += 1 print(a) func1()
执行报错
这里函数对全局变量做了改变,是不允许操作的。
函数内部可以引用全局变量,不能修改。如果要修改,必须要global一下
a = 5 def func1(): global a a += 1 print(a) func1()
执行输出6
三、多个装饰器,装饰一个函数
def wrapper1(func): # func == f函数名 def inner1(): print('wrapper1 ,before func') # 2 func() print('wrapper1 ,after func') # 4 return inner1 def wrapper2(func): # func == inner1 def inner2(): print('wrapper2 ,before func') # 1 func() print('wrapper2 ,after func') # 5 return inner2 @wrapper2 # f = wrapper2(f) 里面的f==inner1 外面的f == inner2 @wrapper1 # f = wrapper1(f) 里面的f==函数名f 外面的f == inner1 def f(): # 3 print('in f') f() # inner2()
执行输出:
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
哪个离函数近,哪个先计算
最底下的先执行
执行顺序如下图:
多个装饰器,都是按照上图的顺序来的
今日作业:
1.写函数,返回一个扑克牌列表,里面有52项,每一项是一个元组 例如:[('红心',2),('草花',2), …('黑桃','A')] 2.写函数,传入n个数,返回字典{'max':最大值,'min':最小值} 例如:min_max(2,5,7,8,4) 返回:{'max':8,'min':2} 3.写函数,专门计算图形的面积 其中嵌套函数,计算圆的面积,正方形的面积和长方形的面积 调用函数area('圆形',圆半径) 返回圆的面积 调用函数area('正方形',边长) 返回正方形的面积 调用函数area('长方形',长,宽) 返回长方形的面积 def area(): def 计算长方形面积(): pass def 计算正方形面积(): pass def 计算圆形面积(): pass 4.写函数,传入一个参数n,返回n的阶乘 例如:cal(7) 计算7*6*5*4*3*2*1 5、编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果(升级题) 5.1.为题目3编写装饰器,实现缓存网页内容的功能:(升级题) 具体:实现下载的页面存放于文件中,如果网页有对应的缓存文件,就优先从文件中读取网页内容,否则,就去下载,然后存到文件中 6给每个函数写一个记录日志的功能, 功能要求:每一次调用函数之前,要将函数名称,时间节点记录到log的日志中。 所需模块: import time struct_time = time.localtime() print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time)) 7、编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码 8,在编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码。这个作业之上进行升级操作: 设置两套密码,一套为京东账号密码,一套为淘宝账号密码保存在文件中。 设置四个函数,分别代表 京东首页,京东超市,淘宝首页,淘宝超市。 循环打印四个选项:东首页,京东超市,淘宝首页,淘宝超市。 供用户选择,用户输入选项后,执行该函数,四个函数都加上认证功能,只要登陆成功一次,在选择其他函数,后续都无需输入用户名和密码。 相关提示:用带参数的装饰器。装饰器内部加入判断,验证不同的账户密码。
答案:
1.写函数,返回一个扑克牌列表,里面有52项,每一项是一个元组
例如:[('红心',2),('草花',2), …('黑桃','A')]
1.1准备基础数据
#颜色 colour = ['黑桃♠','红心♥','梅花♣','方块♦'] #牌面的值 card = list(range(2,11))+['A','J','Q','K']
1.2使用for循环遍历
#颜色 colour = ['黑桃♠','红心♥','梅花♣','方块♦'] #牌面的值 card = list(range(2,11))+['A','J','Q','K'] for i in card: for j in colour: print((j,i))
执行输出:
('黑桃♠', 2)
('红心♥', 2)
('梅花♣', 2)
...
1.3 封装成函数
#颜色 colour = ['黑桃♠','红心♥','梅花♣','方块♦'] #牌面的值 card = list(range(2,11))+['A','J','Q','K'] def poker(*args,**kwargs): show_card = [] for i in kwargs['card']: for j in kwargs['colour']: show_card.append((j, i)) return show_card print(poker(colour=colour,card=card))
执行输出:
[('黑桃♠', 2), ('红心♥', 2), ('梅花♣', 2),...]
老师的代码:
def func(li): l = [] for i in li: #用1~13表示13张牌 for j in range(1,14): l.append((i,j)) return l print(func(['草花', '黑桃', '红桃', '方片']))
思考题,在上述代码的基础上修改一下
A用1表示,2~10表示数字牌,JQK分别表示11,12,13
代码如下:
def func(li): l = [] for i in li: #A用1表示,2~10表示数字牌,JQK分别表示11,12,13 for j in range(1,14): if j == 1: j = 'A' elif j == 11: j = 'J' elif j == 12: j = 'Q' elif j == 13: j = 'K' l.append((i,j)) return l print(func(['草花', '黑桃', '红桃', '方片']))
2.写函数,传入n个数,返回字典{'max':最大值,'min':最小值}
例如:min_max(2,5,7,8,4)
返回:{'max':8,'min':2}
2.1使用内置函数,可以得出最大和最小值
a = (1,2,3) b = {'k1':1,'k2':2} print(max(a)) print(min(b.values()))
执行输出:
3
1
2.2封装成函数
def min_max(*args,**kwargs): dic = {'max':None,'min':None} number = [] #循环位置变量 for i in args: for j in i: number.append(j) # 循环关键字变量 for k in kwargs.values(): number.append(k) #最大值和最小值 dic['max'] = max(number) dic['min'] = min(number) return dic print(min_max([2,6,7,8,3,7,678,3,432,6547],a=1))
执行输出:
{'min': 1, 'max': 6547}
老师的代码:
def func2(*args): return {'max':max(args), 'min':min(args)} print(func2(1,2,3,4,5))
3.写函数,专门计算图形的面积
其中嵌套函数,计算圆的面积,正方形的面积和长方形的面积
调用函数area('圆形',圆半径) 返回圆的面积
调用函数area('正方形',边长) 返回正方形的面积
调用函数area('长方形',长,宽) 返回长方形的面积
def area():
def 计算长方形面积():
pass
def 计算正方形面积():
pass
def 计算圆形面积():
pass
先找出公式
长方形面积公式
S = ab
公式描述:公式中a,b分别为长方形的长和宽,S为长方形的面积。
正方形面积公式
S = a²
公式描述:公式中a为正方形边长,S为正方形面积。
圆的面积公式
S = πr²
公式描述:公式中r为圆的半径,π用3.14表示
写函数雏形
def area(*args,**kwargs): #计算长方形面积 def rectangle(*args,**kwargs): pass #计算正方形面积 def square(*args,**kwargs): pass #计算圆形面积 def circular(*args,**kwargs): pass print(args) ret = area('长方形', '长','宽') print(ret)
执行输出:
('长方形', '长', '宽')
None
填补函数
def area(*args,**kwargs): #计算长方形面积 def rectangle(*args,**kwargs): #print(args) return args[0] * args[1] #计算正方形面积 def square(*args,**kwargs): return args[0] ** 2 #计算圆形面积 def circular(*args,**kwargs): return 3.14 * (args[0] ** 2) #判断参数 if args[0].strip() == '长方形': return rectangle(args[1],args[2]) elif args[0].strip() == '正方形': return square(args[1]) elif args[0].strip() == '圆形': return circular(args[1]) else: return '参数不正确!' ret1 = area('长方形',3,4) ret2 = area('正方形',5) ret3 = area('圆形',6) print(ret1) print(ret2) print(ret3)
执行输出:
12
25
113.04
老师的代码:
def area(*args): #判断参数 if args[0] == '长方形': def 计算长方形面积(): s = args[1]*args[2] return s return 计算长方形面积() elif args[0] == '正方形': def 计算正方形面积(): s = args[1] ** 2 return s return 计算正方形面积() elif args[0] == '圆形': def 计算圆形面积(): s = 3.14 * (args[1] ** 2) return s return 计算圆形面积() print(area('长方形',2,3)) print(area('正方形',5)) print(area('圆形',6))
4.写函数,传入一个参数n,返回n的阶乘
例如:cal(7)
计算7*6*5*4*3*2*1
4.1先用range输出倒序的数字
range(开始,结束,步长)
默认步长为1,如果为-1,表示倒序
for i in range(7,0,-1): print(i)
执行输出:
7
6
5
4
3
2
1
4.2封装函数
def cal(*args,**kwargs): ret = 1 for i in range(args[0],0,-1): ret *= i return ret print(cal(7))
执行输出:
5040
老师的代码:
def func3(n): count = 1 for i in range(n,0,-1): count = count * i return count print(func3(7))
5、编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果(升级题)
5.1.为题目3编写装饰器,实现缓存网页内容的功能:(升级题)
具体:实现下载的页面存放于文件中,如果网页有对应的缓存文件,就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
import urllib.request import os import time def download_index(*args, **kwargs): flag = False def inner(): if os.path.isfile('download.txt') == flag: for i in args: url = 'https://' + str(i) response = urllib.request.urlopen(url).read().decode('utf-8') time.sleep(1) with open('download.txt', encoding='utf-8', mode='w') as f2: f2.write(response) return response else: with open('download.txt', encoding='utf-8', mode='r') as f3: #print(inner.__closure__) return f3.read() return inner print(download_index('www.baidu.com')())
执行输出:
<html>
<head>
<script>
...
</html>
6.给每个函数写一个记录日志的功能,
功能要求:每一次调用函数之前,要将函数名称,时间节点记录到log的日志中。
所需模块:
import time
struct_time = time.localtime()
print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))
6.1准备示例函数
import time def func1(): """ 此函数是测试的 :return: """ print(666) time.sleep(0.3) return True func1() print(func1.__name__) print(func1.__doc__)
执行输出:
666
func1
此函数是测试的
:return:
准备装饰器模板
def wrapper(f): def inner(*args,**kwargs): '''被装饰函数之前''' ret = f(*args,**kwargs) '''被装饰函数之后''' return ret return inner
补充装饰器,完整代码如下:
import time def wrapper(f): def inner(*args,**kwargs): '''被装饰函数之前''' ret = f(*args,**kwargs) '''被装饰函数之后''' #标准时间 struct_time = time.localtime() standard_time = time.strftime("%Y-%m-%d %H:%M:%S",struct_time) print('函数名称:{} 时间节点:{}\n'.format(f.__name__,standard_time)) return ret return inner @wrapper def func1(): """ 此函数是测试的 :return: """ print(666) time.sleep(0.3) return True func1()
执行输出:
666
函数名称:func1 时间节点:2018-04-02 16:25:05
增加写入日志功能
import time def wrapper(f): def inner(*args,**kwargs): '''被装饰函数之前''' ret = f(*args,**kwargs) '''被装饰函数之后''' #标准时间 struct_time = time.localtime() standard_time = time.strftime("%Y-%m-%d %H:%M:%S",struct_time) #写入日志 with open('function_log.txt',encoding='utf-8',mode='a+') as f1: f1.write('函数名称:{} 时间节点:{}\n'.format(f.__name__,standard_time)) return ret return inner @wrapper def func1(): """ 此函数是测试的 :return: """ print(666) time.sleep(0.3) return True func1()
多执行几次程序,查看日志文件function_log.txt
老师的代码:
def wrapper(func): def inner(*args, **kwargs): struct_time = time.localtime() time_now = time.strftime("%Y-%m-%d %H:%M:%S", struct_time) with open('log', encoding='utf-8', mode='a') as f1: f1.write('在时间是%s,执行了%s函数\n' % (time_now, func.__name__)) ret = func(*args, **kwargs) '''函数执行之后操作''' return ret return inner @wrapper def func1(): time.sleep(1) print(555) @wrapper def func2(): time.sleep(2) print(666) func1() func2()
思考题
执行func1和func2必须登录,才能执行。函数执行之后,记录日志
时间: xx年xx月xx日 xx 执行了 xx 函数
代码如下:
import time dic = { 'username':None, 'status':False, } #错误次数 i = 0 def wrapper(func): def inner(*args, **kwargs): # 判断登录状态是否为True if dic['status']: # 执行被装饰行函数 ret = func(*args, **kwargs) return ret else: # 这里需要修改全局变量,要global一下 global i while i < 3: username = input('请输入用户名:').strip() password = input('请输入密码:').strip() with open('register_msg', encoding='utf-8') as f1: for j in f1: j_li = j.strip().split() # ['张三','123'] if username == j_li[0] and password == j_li[1]: # 修改全局变量 dic['username'] = username dic['status'] = True struct_time = time.localtime() time_now = time.strftime("%Y-%m-%d %H:%M:%S", struct_time) with open('log', encoding='utf-8', mode='a') as f1: f1.write('时间:%s %s执行了 %s函数\n' % (time_now,username,func.__name__)) ret = func(*args, **kwargs) return ret else: print('账号或者密码错误,请重新输入%s机会' % (2 - i)) i += 1 '''函数执行之后操作''' #return ret return inner @wrapper def func1(): time.sleep(0.4) print(555) @wrapper def func2(): time.sleep(0.5) print(666) func1() func2()
执行输出:
查看日志
7、编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
7.1 准备函数雏形
def check_login(func): #检查登陆的装饰器 def inner(*args,**kwargs): '''函数被装饰之前''' ret = func(*args,**kwargs) '''函数被装饰之后''' return ret return inner def index(): print("welcome to index page") @check_login def home(): #用户主页 print("welcome to home page") @check_login def bbs(): #bbs页面 print("welcome to bbs page")
填补代码,完整代码如下:
import os #文件名 file_name = 'user_list.txt' #用户状态 user_status = {'username':None,'status':False} def check_login(func): #检查登陆的装饰器 def inner(*args,**kwargs): #print(user_status['status']) if user_status['status']: r = func(*args,**kwargs) return r else: print("\033[41;1m请先登录!\033[0m") #返回首页 index() return inner #首页 def index(): print("welcome to index page") global user_status while True: username = input("username:").strip() password = input("password:").strip() # 判断文件是否存在 if os.path.exists(file_name) == False: with open(file_name, encoding='utf-8', mode='w') as mk: mk.write('xiao 123') with open(file_name, encoding='utf-8', mode='r') as f1: for i in f1: # 去空格,以空格切割,转换为列表 li = i.strip().split() # [张三,123] # 判断用户名和密码是否匹配 if username == li[0] and password == li[1]: result = True # 当找到匹配时,跳出循环 break else: result = False # 当整个用户列表遍历完成之后,再判断result if result: #更改全局变量 user_status['username'] = username user_status['status'] = True break else: print('用户名和密码不正确,请重新输入') @check_login def home(): #用户主页 print("welcome to home page") @check_login def bbs(): #bbs页面 print("welcome to bbs page") index() home() bbs()
执行输出:
老师的代码:
必须提前创建好文件register_msg,默认内容为'张三 123'
#全局变量,用户状态 dic = { 'username':None, 'status':False, } #错误次数 i = 0 def wrapper(func): def inner(*args, **kwargs): #判断登录状态是否为True if dic['status']: #执行被装饰行函数 ret = func(*args, **kwargs) return ret else: #这里需要修改全局变量,要global一下 global i while i < 3: username = input('请输入用户名:').strip() password = input('请输入密码:').strip() with open('register_msg',encoding='utf-8') as f1: for j in f1: j_li = j.strip().split() # ['张三','123'] if username == j_li[0] and password == j_li[1]: #修改全局变量 dic['username'] = username dic['status'] = True ret = func(*args, **kwargs) return ret else: print('账号或者密码错误,请重新输入%s机会' % (2-i)) i += 1 return inner @wrapper def article(): print('文章') @wrapper def diary(): print('日记') @wrapper def comment(): print('评论') @wrapper def file(): print('文件') article() diary() comment() file()
8,在编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码。这个作业之上进行升级操作:
设置两套密码,一套为京东账号密码,一套为淘宝账号密码保存在文件中。
设置四个函数,分别代表 京东首页,京东超市,淘宝首页,淘宝超市。
循环打印四个选项:东首页,京东超市,淘宝首页,淘宝超市。
供用户选择,用户输入选项后,执行该函数,四个函数都加上认证功能,只要登陆成功一次,在选择其他函数,后续都无需输入用户名和密码。
相关提示:用带参数的装饰器。装饰器内部加入判断,验证不同的账户密码。
不废话,直接贴代码
# -*- coding: utf-8 -*- import os #文件名 file_jd = 'jd.txt' file_taobao = 'taobao.txt' #用户状态 user_status = {'username':None,'status':False,'user_type':None} def username_password(file_name,username,password): ''' #判断用户名和密码是否匹配 :param username: 用户名 :param password: 密码 :return: True 匹配成功 False 匹配失败 ''' if username == '' or password == '': return '用户名或者密码不能为空!' with open(file_name, encoding='utf-8', mode='r') as f3: for i in f3: # print(i) # 去空格,以空格切割,转换为列表 li = i.strip().split() # [张三,123] # 判断用户名和密码是否匹配 if username == li[0] and password == li[1]: result = True #result = {'msg':True,'level':li[2]} # 当找到匹配时,跳出循环 break else: result = False #result = {'msg': False, 'level': li[2]} # 当整个用户列表遍历完成之后,再return return result def check_login(func): #检查登陆的装饰器 def inner(*args,**kwargs): if user_status['status']: r = func(*args,**kwargs) return r else: print("\033[41;1m请先登录!\033[0m") #返回首页 login() func(*args, **kwargs) return inner def login(): #登录程序 global user_status while True: print('请选择用户类型\n1.京东帐户\n2.淘宝账户\n') user_type = input('请输入编号: ').strip() if user_type == '1' or user_type == '2': break else: print("\033[41;1m输入错误,请重新输入!\033[0m") while True: username = input('请输入用户名,或输入q返回主页:').strip() if username.upper() == 'Q': index() if username == '': print("\033[41;1m用户名不能为空!\033[0m") password = input('请输入密码:').strip() if password == '': print("\033[41;1m密码不能为空!\033[0m") if username != '' and password != '': #break # 判断文件是否存在 if os.path.exists(file_jd) == False or os.path.exists(file_taobao) == False: with open(file_jd, encoding='utf-8', mode='w') as f_jd: f_jd.write('xiao 123') with open(file_taobao, encoding='utf-8', mode='w') as f_taobao: f_taobao.write('tao 123') if user_type == '1': file_name = file_jd user_type = '京东帐户' else: file_name = file_taobao user_type = '淘宝帐户' # 执行验证用户名和密码函数 #print(file_name,username, password) result = username_password(file_name,username, password) if result: print('登陆成功!\n') user_status['username'] = username user_status['status'] = True user_status['user_type'] = user_type index() else: print("\033[41;1m用户名或密码错误!\033[0m") #首页 def index(): menu = ['京东首页','京东超市','淘宝首页','淘宝超市','退出'] #菜单函数名对照表 menu_func = ['jd_index','jd_supermarket','taobao_index','taobao_supermarket','exit'] print("꧁欢迎访问购物商城꧂".center(30,'❀')) status = '在线' if user_status['status'] == True else '未登录' info = '\n当前登陆用户:{} 状态: {} 用户类型:{}\n'.format(user_status['username'], status, user_status['user_type']) print(info.rjust(15)) for i in range(len(menu)): print('{}\t{}'.format(i + 1, menu[i])) print("".center(35, '☪')) while True: number = input("请输入序号:").strip() if number.isdigit(): number = int(number) if number > 0 and number <= len(menu): #执行菜单函数 eval(menu_func[number-1])() else: print('输入错误,请重新输入!') @check_login def jd_index(): #京东首页 #print("欢迎访问 京东首页") print("\033[32m欢迎访问 京东首页\033[0m") @check_login def jd_supermarket(): #京东超市 #print("欢迎访问 京东超市") print("\033[32m欢迎访问 京东超市\033[0m") @check_login def taobao_index(): #淘宝首页 #print("欢迎访问 淘宝首页") print("\033[32m欢迎访问 淘宝首页\033[0m") @check_login def taobao_supermarket(): #淘宝超市 #print("欢迎访问 淘宝超市") print("\033[32m欢迎访问 淘宝超市\033[0m") #执行函数 if __name__ == '__main__': index()
执行输出:
老师的代码:
dic = { 'username':None, 'status':False, } i = 0 def login(flag): def wrapper(func): def inner(*args, **kwargs): #判断用户状态是否为True if dic['status']: ret = func(*args, **kwargs) return ret else: global i while i < 3: username = input('请输入用户名(用%s账号):' % flag).strip() password = input('请输入密码:').strip() with open('user_pwd',encoding='utf-8') as f1: #读取一行,因为文件只有一行内容 msg_dic = eval(f1.readline()) # {'微信': {'password': '123', 'username': '老男孩'}, 'qq': {'password': '123', 'username': '老男孩1'}} if username == msg_dic[flag]['username'] and password == msg_dic[flag]['password']: #修改全局变量,这里不用global,因为它是可变类型 dic['username'] = username dic['status'] = True #执行被装饰的函数 ret = func(*args, **kwargs) return ret else: print('您输入的用户或者密码错误,请重新输入,还有%s次机会' % (2-i)) i += 1 return inner return wrapper @login('微信') def taobao_home(): print('淘宝首页') @login('微信') def taobao_shop(): print('淘宝超市') @login('qq') def jingdong_home(): print('京东首页') @login('qq') def jingdong_shop(): print('京东超市') #菜单列表,建议使用此方式 choice_dict = { #序号:函数名 1: taobao_home, 2: taobao_shop, 3: jingdong_home, 4: jingdong_shop, 5: exit, } while True: print('1 淘宝首页\n2 淘宝超市\n3 京东首页\n4 京东超市\n5 退出') choice_num = input('请选择输入的序号:').strip() if choice_num.isdigit(): choice_num = int(choice_num) #判断数字范围 if 0 < choice_num <= len(choice_dict): #执行函数 choice_dict[choice_num]() else: print('请输入范围内的序号') else: print('您输入的有非法字符,请重新输入')
执行输出: