装饰器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 付款完成

第一次想要付款时,因为没有登录,所有不能付款,需要输入用户名和密码,再付款

第二次付款时,因为第一次已经登录过了,因此可以直接付款

原文地址:https://www.cnblogs.com/vigossr/p/11413193.html