Python3 装饰器
一 什么是装饰器呢?
装饰器本质上来说就是函数,功能就是为其它函数添加附加功能。
原则:
- 不修改被修饰函数的源代码
- 不修改被修饰函数的调用方式
组织结构:
装饰器=高阶函数+函数嵌套+闭包
实例1(Python3.0+):
# 使用高阶函数试图完成装饰器 import time # 定义函数foo def foo(): time.sleep(3) print('你好啊,林师傅') # 定义函数test来装饰foo函数,计算foo函数的运行时间 def test(func): start_time = time.time() print(func) func() stop_time=time.time() print('函数的运行时间:%s' %(stop_time-start_time)) test(foo) # 改变了被修饰函数(foo())的调用方式,不满足装饰器的特性,所以不是合格的装饰器
实例2(Python3.0+):
简单装饰器的创建思路
import time # 先架设装饰器的架子:高阶函数+函数嵌套+闭包 def timer(func): # func=test def wrapper(): start_time=time.time() # print(func) func() # 就是在运行test() stop_time=time.time() print('函数的运行时间:%s' %(stop_time-start_time)) return wrapper def test(): time.sleep(2) print('函数运行结果') # test返回的就是wrapper test=timer(test) # 执行test()就相当于执行wrapper() test() ''' 以上例子实现了装饰器的部分功能: 1、没有改变原有函数的源代码,但是改变了函数的调用方式 ''' # 思考:怎么才能不改变被修饰函数的调用方式呢,我们可以采用语法糖的方式。 # 语法糖 @ # @timer 就相当于test=timer(test) import time # 架设装饰器的架子:高阶函数+函数嵌套+闭包 def timer(func): # func=test def wrapper(): start_time=time.time() # print(func) func() # 就是在运行test() stop_time=time.time() print('函数的运行时间:%s' %(stop_time-start_time)) return wrapper @timer def test(): time.sleep(2) print('函数运行结果') test() # 如果我想打印被修饰函数的返回值呢?: # 实例1: # import time # 装饰器的架子:高阶函数+函数嵌套+闭包 def timer(func): # func=test def wrapper(): start_time=time.time() # print(func) func() # 就是在运行test() stop_time=time.time() print('函数的运行时间:%s' %(stop_time-start_time)) return wrapper @timer # test = timer(test) def test(): time.sleep(2) print('函数运行结束') return '这是test的返回值' res=test() # test()实际上运行的是wrapper() 原因:1.@timer 等于 test=timer(test) ,所以实际上运行test()相当于timer()(),也就是test=wrapper print(res) # 实际上打印的是wrapper的返回值,但wrapper函数没有ruturn返回值,所以得到的结果为None ''' 函数运行结束 函数的运行时间:2.0001144409179688 None ''' # 实例1中没有实现打印被修饰函数返回值的功能,看看以下代码呢; # 实例2: # import time # 装饰器的架子:高阶函数+函数嵌套+闭包 def timer(func): # func=test def wrapper(): start_time=time.time() res=func() # print(func) # func() # 就是在运行test() stop_time=time.time() print('函数的运行时间:%s' %(stop_time-start_time)) return res return wrapper @timer # test = timer(test) def test(): time.sleep(2) print('函数运行结束') return '这是test的返回值' print(test()) ''' 打印结果: 函数运行结束 函数的运行时间:2.0001142024993896 这是test的返回值 '''
实例3(Python3.0+):
实例2中虽然已经实现了装饰器的功能,但是被修饰的函数是没有形参的,如果我们在被修饰的函数中定义形参呢,那实例2中的装饰器就不能完成这个任务了吧??
# 带参数的装饰器 # import time # 装饰器的架子:高阶函数+函数嵌套+闭包 def timer(func): # func=test def wrapper(*args,**kwargs): # 相当于定义函数 def test(*args,**wargs): start_time=time.time() res=func(*args,**kwargs) # 就是在运行test() # print(func) # func() # 就是在运行test() stop_time=time.time() print('函数的运行时间:%s' %(stop_time-start_time)) return res return wrapper # test=wrapper @timer # test = timer(test) def test(name,age): time.sleep(2) print('函数运行结束') print('test函数运行完毕,名字是%s 年龄是%s' %(name,age)) return '这是test的返回值' # test() print(test('lvcm',19)) ''' 运行结果: 函数运行结束 test函数运行完毕,名字是lvcm 年龄是19 函数的运行时间:2.0001144409179688 这是test的返回值 '''
二 练习题:
1、模仿京东商城登录
# 简单的京东登录架构 # 进入京东主页 def index(): print('欢迎来到京东主页') # 进入个人主页 def home(name): print('欢迎回家%s' %name) # 打印购物车物品 def shopping_car(name): print('%s购物车里有[%s,%s,%s]'%(name,'丝袜','娃娃','奶茶')) # 打印个人订单 def order(): print('您的订单是.......') index() home('lvcm') shopping_car('lvcm') order() # 需求:给每个函数加上一个用户登录的验证功能 # # 定义用户默认登录状态 dict_user={'username':None,'login':False} # 定义用户登录验证装饰器 def auth_login(func): def wrapper(*args,**kwargs): # print('您未登录,请先登录,谢谢...') while True: if dict_user['username']=='lvcm' and dict_user['login'] == True: res=func(*args,**kwargs) return res user_name=input('请输入用户名:').strip() user_passwd=input('请输入密码:').strip() if user_name=='lvcm' and user_passwd=='123': print('%s登录成功' %user_name) dict_user['username']=user_name dict_user['login']=True break else: print("用户名密码错误,请重新输入") res=func(*args,**kwargs) return res return wrapper @auth_login def index(): print('欢迎来到京东主页') @auth_login def home(name): print('欢迎回家%s' %name) @auth_login def shopping_car(name): print('%s购物车里有[%s,%s,%s]'%(name,'丝袜','娃娃','奶茶')) @auth_login def order(): print('您的订单是.......') index() ''' 运行结果: 请输入用户名:lvcm 请输入密码:123 lvcm登录成功 欢迎来到京东主页 ''' home('lvcm') ''' 运行结果: 请输入用户名:lvcm 请输入密码:123 lvcm登录成功 欢迎回家lvcm ''' shopping_car('lvcm') ''' 运行结果: 请输入用户名:lvcm 请输入密码:123 lvcm登录成功 lvcm购物车里有[丝袜,娃娃,奶茶] ''' order() ''' 运行结果: 请输入用户名:lvcm 请输入密码:123 lvcm登录成功 您的订单是....... '''
上述例题中我们模仿了京东个人登录验证功能,但是代码中发现一个很有意思的问题,就是没次刷新页面时都要验证登录,这是很不合理的,其实登录验证一次就可以了。
2、复杂的仿京东程序
# 定义用户列表 user_list=[ {'name':'lvzf','passwd':'123'}, {'name':'zhangjm','passwd':'123'}, {'name':'lvcm','passwd':'123'}, {'name':'muyb','passwd':'123'}, ] # 定义用户登录初始状态 current_dict={'username':None,'login':False} def auth_login(func): def wrapper(*args,**kwargs): # print('您未登录,请先登录,谢谢...') while True: if current_dict['username'] and current_dict['login']: res=func(*args,**kwargs) return res username=input('请输入用户名:').strip() userpasswd=input('请输入密码:').strip() for user_dict in user_list: if username==user_dict['name'] and userpasswd==user_dict['passwd']: print('%s登录成功' %username) current_dict['username']=username current_dict['login']=True break else: print("用户名密码错误,请重新输入") res=func(*args,**kwargs) return res return wrapper print('before is ') @auth_login def index(): print('欢迎来到京东主页') @auth_login def home(name): print('欢迎回家%s' %name) @auth_login def shopping_car(name): print('%s购物车里有[%s,%s,%s]'%(name,'丝袜','娃娃','奶茶')) @auth_login def order(): print('您的订单是.......') index() home('lvcm') shopping_car('lvcm') order()