装饰器decorator
Tutorial:
https://www.python-course.eu/python3_decorators.php
先运行装饰器,再运行被包装的函数
装饰器使用的特点:
1 必须用函数作为参数传递给另一个函数
2 要有闭包的特点
装饰器范例:
1 #定义一个装饰器: 用函数作为参数传给另一个函数 2 def decorator(func): 3 a=100 4 print('wrapper外层打印测试') 5 def wrapper(): 6 print('------>111111') 7 func() 8 print('------>222222') 9 print(a) 10 print('wrapper加载完成') 11 return wrapper 12 13 #使用装饰器:要给house()函数加装饰器,则在def house()上面@decorator 14 @decorator #此处的@,表示运行decorator() 15 def house(): 16 print('我是毛坯房') 17 #house() 18 print(house) 19 20 #不改变原函数的前提下,对其进行修改 21 22 def house1(): 23 house() 24 print('刷漆') 25 print('铺地板') 26 #house1() #等同于装饰器的效果 27 house() 28 ''' 29 @decorator表示: 30 1 house是被装饰函数 31 2 将被装饰函数作为参数传给装饰器decorator 32 3 底层执行了装饰器函数decorator 33 因此一旦@了,则会执行decorator里面的print命令 34 4 将返回值赋值给house 35 decorator返回的wrapper并没有变量接收,但默认是由house接收,参考print(house)结果 36 print(house) - <function decorator.<locals>.wrapper at 0x050B32B8> 37 '''
范例2:
1 import time 2 def decorate(func): 3 def wrapper(): 4 print('正在校验。。。') 5 time.sleep(2) 6 print('校验完成') 7 func() 8 return wrapper 9 10 @decorate 11 def f1(): 12 print('---f1---') 13 @decorate 14 def f2(): 15 print('---f2---') 16 17 f1() 18 f2()
结果:
1 正在校验。。。 2 校验完成 3 ---f1--- 4 正在校验。。。 5 校验完成 6 ---f2---
3. 带参数的装饰器:
1 #装饰器范例2,带参数 2 import time 3 def decorate(func): #不论传过来的是什么参数,都可以识别,就是万能装饰器 4 def wrapper(*argv, **kwargv): #*argv这种只能接收非关键字参数,**kwargv可以接收关键字参数, 5 #**kwargv会自动把传过来的变为字典{'class1':1905} 6 print('正在校验。。。') 7 time.sleep(2) 8 print('校验完成') 9 func(*argv, **kwargv) #func()可能是f1,f2,f3 10 return wrapper 11 12 @decorate 13 def f1(n): 14 print('---f1---',n) 15 16 @decorate 17 def f2(name, age): 18 print('---f2---',name,age) 19 20 @decorate 21 def f3(students, class1 = '1905'): 22 print('{}班级的学生如下:'.format(class1)) 23 for stu in students: 24 print(stu) 25 26 def f4(): 27 print('---f4---') 28 29 f1(5) #经过装饰器装饰后的f1已经是wrapper了,因此需要让wrapper也能接收一个参数 30 f2('haha','5') 31 f3([1,2], class1='1904') 32 f3([1,2]) 33 #f4()
结果:
1 正在校验。。。 2 校验完成 3 ---f1--- 5 4 正在校验。。。 5 校验完成 6 ---f2--- haha 5 7 正在校验。。。 8 校验完成 9 1904班级的学生如下: 10 1 11 2 12 正在校验。。。 13 校验完成 14 1905班级的学生如下: 15 1 16 2
4. 多层装饰器:
1 ''' 2 如果装饰器是多层的,哪个装饰器离要被装的函数近,就先执行哪个装饰器 3 ''' 4 5 def decorator1(func): 6 print('------1, start') #当使用装饰器时,@后,就会打印装饰器内的内容 7 def wrapper(*argv, **kwargv): 8 func() 9 print('刷漆') 10 11 print('------1, end') 12 return wrapper 13 14 def decorator2(func): 15 print('------2, start') 16 def wrapper(*argv, **kwargv): 17 func() 18 print('铺地板') 19 print('------2, end') 20 return wrapper 21 22 23 @decorator2 #此处的顺序是哪个装饰器离要被装的函数近,就先执行哪个装饰器,@的时候会执行装饰器内的print 24 @decorator1 25 def house(): 26 print('我是毛坯房') 27 28 house()
结果:
1 ------1, start 2 ------1, end 3 ------2, start 4 ------2, end 5 我是毛坯房 6 刷漆 7 铺地板
5. 带参数的装饰器
1 #带参数的装饰器 2 ''' 3 带参数的装饰器是三层的 4 5 ''' 6 def outer(a): #第一层用来接收装饰器传过来的参数的 100 7 def decorate(func): #第二层负责接收内层函数的 8 def wrapper(*argv, **kwargv): #第三层负责接收函数的实参的 20199093 9 func(*argv) 10 print('--->铺地砖{}块'.format(a)) 11 return wrapper #第二层返回的是第三层的函数名 12 return decorate #第一层函数返回的是第二层的函数名 13 14 #在装饰器中可能传参 15 @outer(a=10) 16 def house(time): 17 print('我{}拿到钥匙,是毛坯房'.format(time)) 18 19 @outer(100) 20 def street(): 21 print('新修的街道叫哈哈') 22 ''' 23 装饰器的目的在于,让有共同点的代码都被具有该共同点的装饰器锁装饰 24 ''' 25 26 house('20190903') 27 28 street()
结果:
1 我20190903拿到钥匙,是毛坯房 2 --->铺地砖10块 3 新修的街道叫哈哈 4 --->铺地砖100块
6. 装饰器应用
1 #开发:登录验证 2 import time 3 4 islogin = False #默认没有登录的 5 #定义一个登录函数 6 def login(): 7 username = input('输入用户名: ') 8 password = input('输入密码:') 9 if username == 'admin' and password == '123456': 10 return True 11 else: 12 return False 13 14 #定义装饰器进行付款验证的 15 def login_required(func): 16 def wrapper(*argv, **kwargv): 17 global islogin 18 print('------付款------') 19 #验证用户是否登录 20 if islogin: 21 func(*argv, **kwargv) 22 else: 23 #跳转到登录界面 24 print('用户没有登录,不能付款') 25 islogin = login() 26 print('result: ',islogin) 27 return wrapper 28 29 30 31 @login_required 32 def pay(money): 33 print('正在付款,付款金额是:{}元'.format(money)) 34 print('付款中。。。') 35 time.sleep(2) 36 print('付款完成') 37 38 #调用付款: 39 pay(100) #相当于wrapper(100),argv= 100 40 41 pay(80) 42 #调用第一个pay时没付款成功,跳到登录界面了,调用第二个pay时直接付款成功,因为pay(100)时已经登录成功了
结果:
1 ------付款------ 2 用户没有登录,不能付款 3 输入用户名: admin 4 输入密码:123456 5 result: True 6 ------付款------ 7 正在付款,付款金额是:80元 8 付款中。。。 9 付款完成
第一次想要付款时,因为没有登录,所有不能付款,需要输入用户名和密码,再付款
第二次付款时,因为第一次已经登录过了,因此可以直接付款