一、什么是装饰器
装饰器本质就是函数,功能是为其他函数附加功能
二、装饰器遵循的原则
1、不修改被修饰函数的源代码
2、不修改被修饰函数的调用方式
三、实现装饰器的知识储备
装饰器=高阶函数+函数嵌套+闭包
示例1: 用函数实现
1 #计算从1-100,统计函数运行时间 2 3 import time 4 def cal(l): 5 start_time=time.time() 6 res=0 7 for i in l: 8 time.sleep(0.1) 9 res+=i 10 stop_time = time.time() 11 print('函数的运行时间是%s' %(stop_time-start_time)) 12 return res 13 14 print(cal(range(100))) #直接打印得到运行的时间
执行结果:
1 函数的运行时间是10.007169723510742 2 4950
示例2:用装饰器实现函数运行时间
1 import time 2 def timmer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 res=func(*args,**kwargs) 6 stop_time = time.time() 7 print('函数运行时间是%s' %(stop_time-start_time)) 8 return res 9 return wrapper 10 11 @timmer #调用装饰器 12 def cal(l): 13 res=0 14 for i in l: 15 time.sleep(0.1) 16 res+=i 17 return res 18 19 res=cal(range(20)) 20 print(res)
四、高阶函数高阶函数定义
1.函数接收的参数是一个函数名
2.函数的返回值是一个函数名
3.满足上述条件任意一个,都可称之为高阶函数
高阶函数示例如下:
示例1:函数接收的参数是一个函数名
1 #1.函数接收的参数是一个函数名 2 import time 3 def foo(): 4 time.sleep(3) 5 print('你好啊林师傅') 6 7 def test(func): #test高阶函数 8 # print(func) #获取到内存地址 9 start_time=time.time() 10 func() 11 stop_time = time.time() 12 print('函数运行时间是 %s' % (stop_time-start_time)) 13 # foo() 14 test(foo)
执行结果:
1 你好啊林师傅 2 函数运行时间是 3.0003013610839844 3 来自foo
示例2:
1 def foo(): 2 print('from the foo') 3 def test(func): 4 return func 5 6 # res=test(foo) 7 # # print(res) 8 # res() 9 10 foo=test(foo) 11 # # print(res) 12 foo() 13 14 import time 15 def foo(): 16 time.sleep(3) 17 print('来自foo') 18 19 #不修改foo源代码 20 #不修改foo调用方式
示例3:
1 #多运行了一次,不合格 2 import time 3 def foo(): 4 time.sleep(3) 5 print('来自foo') 6 7 def timer(func): 8 start_time=time.time() 9 func() 10 stop_time = time.time() 11 print('函数运行时间是 %s' % (stop_time-start_time)) 12 return func 13 foo=timer(foo) 14 foo()
示例4:
1 #没有修改被修饰函数的源代码,也没有修改被修饰函数的调用方式,但是也没有为被修饰函数添加新功能 2 import time 3 def foo(): 4 time.sleep(3) 5 print('来自foo') 6 7 def timer(func): 8 start_time=time.time() 9 return func 10 stop_time = time.time() 11 print('函数运行时间是 %s' % (stop_time-start_time)) 12 13 foo=timer(foo) 14 foo()
执行结果:
1 来自foo
结论:高阶函数,满足不了装饰器的功能。
高阶函数总结:
1.函数接收的参数是一个函数名
作用:在不修改函数源代码的前提下,为函数添加新功能,
不足:会改变函数的调用方式
2.函数的返回值是一个函数名
作用:不修改函数的调用方式
不足:不能添加新功能
五、函数的嵌套
1、什么是函数的嵌套?
通过在函数内部def的关键字再声明一个函数即为嵌套
示例:
1 def father(name): 2 def son(): 3 print('我的爸爸是%s' %name) 4 def grandson(): 5 name='就是我自己' 6 print('我的爷爷是%s' %name) 7 grandson() 8 son() 9 father('linhaifeng')
执行结果:
1 我的爸爸是linhaifeng 2 3 我的爷爷是就是我自己
六、闭包
1 #闭包:在一个作用域里放入定义变量,相当于打了一个包 2 def father(auth_type): 3 # print('from father %s' %name) 4 def son(): 5 # name='linhaifeng_1' 6 # print('我的爸爸是%s' %name) 7 def grandson(): 8 print('我的爷爷是%s' %auth_type) 9 grandson() 10 # print(locals()) 11 son() 12 # father('linhaifeng') 13 father('filedb')
执行结果:
1 我的爷爷是filedb
七、无参装饰器
无参装饰器=高级函数+函数嵌套
1、基本框架
1 #这就是一个实现一个装饰器最基本的架子 2 def timer(func): 3 def wrapper(): 4 func() 5 6 return wrapper
2、基本装饰器(基本框架+参数+功能+返回值+使用装饰器+语法糖@)
import time def timmer(func): #func=test def wrapper(): # print(func) start_time=time.time() func() #就是在运行test() stop_time = time.time() print('运行时间是%s' %(stop_time-start_time)) return wrapper @timmer #test=timmer(test) #在函数名前面加个@ ,这就是语法糖 def test(): time.sleep(3) print('test函数运行完毕') test()
代码说明:
1 # res=timmer(test) #返回的是wrapper的地址 2 # res() #执行的是wrapper() 3 # 4 # test=timmer(test) #返回的是wrapper的地址 5 # test() #执行的是wrapper() 6 # 7 # @timmer 就相当于 test=timmer(test)
执行结果:
1 test函数运行完毕 2 运行时间是3.000155210494995
3、加上返回值
1 import time 2 def timmer(func): #func=test 3 def wrapper(): 4 start_time=time.time() 5 res=func() #就是在运行test() 6 stop_time = time.time() 7 print('运行时间是%s' %(stop_time-start_time)) 8 return res 9 return wrapper 10 11 @timmer #test=timmer(test) 12 def test(): 13 time.sleep(3) 14 print('test函数运行完毕') 15 return '这是test的返回值' 16 17 res=test() #就是在运行wrapper 18 print(res)
执行结果:
1 test函数运行完毕 2 运行时间是3.0001416206359863 3 这是test的返回值
4、加上参数
1 import time 2 def timmer(func): #func=test1 3 def wrapper(*args,**kwargs): #test('linhaifeng',age=18) args=('linhaifeng') kwargs={'age':18} 4 start_time=time.time() 5 res=func(*args,**kwargs) #就是在运行test() func(*('linhaifeng'),**{'age':18}) 6 stop_time = time.time() 7 print('运行时间是%s' %(stop_time-start_time)) 8 return res 9 return wrapper 10 11 # @timmer #test=timmer(test) 12 def test(name,age): 13 time.sleep(3) 14 print('test函数运行完毕,名字是【%s】 年龄是【%s】' %(name,age)) 15 return '这是test的返回值' 16 17 @timmer 18 def test1(name,age,gender): 19 time.sleep(1) 20 print('test1函数运行完毕,名字是【%s】 年龄是【%s】 性别【%s】' %(name,age,gender)) 21 return '这是test的返回值' 22 23 # res=test('linhaifeng',age=18) #就是在运行wrapper 24 # # print(res) 25 # test1('alex',18,'male') 26 27 test1('alex',18,'male')
执行结果:
1 test1函数运行完毕,名字是【alex】 年龄是【18】 性别【male】 2 运行时间是1.0007386207580566
八、装饰器应用案例
写一个模拟京东网站,用户认证登录网站和购物加入购物车功能程序
实现功能:用装饰器给所有函数加上验证功能
1、基本框架
1 def index(): 2 pass 3 4 def home(): 5 pass 6 7 def shopping_car() 8 pass 9 10 def order() 11 pass
2、开始实现
示例1:没有判断验证方式,直接就显示购物车结果。
1 user_list=[ 2 {'name':'alex','passwd':'123'}, 3 {'name':'linhaifeng','passwd':'123'}, 4 {'name':'wupeiqi','passwd':'123'}, 5 {'name':'yuanhao','passwd':'123'}, 6 ] 7 current_dic={'username':None,'login':False} 8 9 def auth(auth_type='filedb'): 10 def auth_func(func): 11 def wrapper(*args,**kwargs): 12 print('认证类型是',auth_type) 13 if auth_type == 'filedb': 14 if current_dic['username'] and current_dic['login']: 15 res = func(*args, **kwargs) 16 return res 17 username=input('用户名:').strip() 18 passwd=input('密码:').strip() 19 for user_dic in user_list: 20 if username == user_dic['name'] and passwd == user_dic['passwd']: 21 current_dic['username']=username 22 current_dic['login']=True 23 res = func(*args, **kwargs) 24 return res 25 else: 26 print('用户名或者密码错误') 27 elif auth_type == 'ldap': 28 print('鬼才特么会玩') 29 res = func(*args, **kwargs) 30 return res 31 else: 32 print('鬼才知道你用的什么认证方式') 33 res = func(*args, **kwargs) 34 return res 35 36 return wrapper 37 return auth_func 38 39 @auth(auth_type='filedb') #auth_func=auth(auth_type='filedb')-->@auth_func 附加了一个auth_type --->index=auth_func(index) 40 def index(): 41 print('欢迎来到京东主页') 42 43 @auth(auth_type='ldap') 44 def home(name): 45 print('欢迎回家%s' %name) 46 # 47 @auth(auth_type='sssssss') 48 def shopping_car(name): 49 print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃')) 50 51 # print('before-->',current_dic) 52 # index() 53 # print('after--->',current_dic) 54 # home('产品经理') 55 shopping_car('产品经理')
执行结果:
1 认证类型是 sssssss 2 鬼才知道你用的什么认证方式 3 产品经理的购物车里有[奶茶,妹妹,娃娃]
示例2 :给他加上验证功能装饰器(判断用户和密码,跟字典里的用户和密码进行比对)
1 user_list=[ 2 {'name':'alex','passwd':'123'}, 3 {'name':'linhaifeng','passwd':'123'}, 4 {'name':'wupeiqi','passwd':'123'}, 5 {'name':'yuanhao','passwd':'123'}, 6 ] 7 current_dic={'username':None,'login':False} 8 9 10 def auth_func(func): 11 def wrapper(*args,**kwargs): 12 if current_dic['username'] and current_dic['login']: 13 res = func(*args, **kwargs) 14 return res 15 username=input('用户名:').strip() 16 passwd=input('密码:').strip() 17 for user_dic in user_list: 18 if username == user_dic['name'] and passwd == user_dic['passwd']: 19 current_dic['username']=username 20 current_dic['login']=True 21 res = func(*args, **kwargs) 22 return res #返回值 23 else: 24 print('用户名或者密码错误') 25 26 return wrapper 27 28 @auth_func #加证功能,也是装饰器 29 def index(): 30 print('欢迎来到京东主页') 31 32 @auth_func 33 def home(name): 34 print('欢迎回家%s' %name) 35 36 @auth_func 37 def shopping_car(name): 38 print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃')) 39 40 print('before-->',current_dic) 41 index() 42 print('after--->',current_dic) 43 home('产品经理') 44 shopping_car('产品经理')
执行结果:
1 before--> {'username': None, 'login': False} 2 用户名:alex #输入字典里的用户名和密码,才能登录成功。 3 密码:123 4 欢迎来到京东主页 5 after---> {'username': 'alex', 'login': True} 6 欢迎回家产品经理 7 产品经理的购物车里有[奶茶,妹妹,娃娃]