装饰器
# 简介
装饰器【Decorator】:使其他函数在不需要做任何代码的变动下,为函数添加功能,装饰器的返回值也是一个函数。
本质:装饰器的本质就是一个闭包,其作用是将一个函数作为参数,返回另一个函数
- 装饰器函数运行在函数定义的时候
- 装饰器需要返回一个可执行的对象
- 装饰器返回的可执行对象要兼容函数f的参数
装饰器条件:
- 外部函数中定义了内部函数
- 外部函数一定要有返回值,返回的值是:内部函数名
- 内部函数调用外部函数传递的需要被装饰的函数
- 函数作为外层函数参数
使用装饰器:
@装饰器名字
def 函数名():
pass
1
2
3
2
3
# 简单的装饰器
在闭包的前提下引用函数作为外层函数的参数
import time
# 装饰器带参数
def zhuang1(func): # 1. 接收f1函数作为参数
def wrapper(*args, **kwargs): # 这里就要加*args,**kwargs 2.外部函数中定义了内部函数
print("正在校验中.....")
time.sleep(2)
print("校验完毕.....")
func(*args, **kwargs) # 调用原函数f1 3.内部函数调用外部函数传递的需要被装饰的函数
return wrapper # 把装饰器在返回给f1 4.外部函数一定要有返回值,返回的值是:内部函数名
@zhuang1
def f1():
print("我是户主one------one")
f1()
正在校验中.....
校验完毕.....
我是户主one------one
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 装饰的函数带有参数
import time
# 装饰器带参数
def zhuang1(func): # 接收f1
def wrapper(*args, **kwargs): # 这里就要加*args,**kwargs
print("正在校验中.....")
time.sleep(2)
print("校验完毕.....")
# 调用原函数
func(*args, **kwargs)
return wrapper # 把装饰器在返回给f1
sum = 10000
@zhuang1
def f1(sum):
print("我是户主one------one", sum)
f1(sum)
@zhuang1
def f2(sum, name="abc"):
print("我是户主{}-----two".format(name), sum)
f2(sum)
@zhuang1
def f2(sum, name="aaaaaa"):
print("我是户主{}-----two".format(name), sum)
f2(sum, name="adfafasdasd") # 覆盖了name的值
正在校验中.....
校验完毕.....
我是户主one------one 10000
正在校验中.....
校验完毕.....
我是户主abc-----two 10000
正在校验中.....
校验完毕.....
我是户主adfafasdasd-----two 10000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 装饰的函数有返回值
# 如果装饰的函数有返回值需要在装饰器的内部函数中用return返回 装饰函数的运行结果
def say(func):
def inner():
print("-----2-----")
return func() # 这里一定要返回原函数
return inner
@say
def show():
return "-----1-----"
print(show())
-----2-----
-----1-----
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 使用多个装饰器装饰同一个函数
'''
如果装饰器是多层的,谁距离函数最近就优先使用哪个装饰器
'''
def zhuangfeng1(func): # 定义装饰器1
print("-----one---start")
def warper():
print("刷漆..")
return func() # 返回原函数
print("end")
return warper
def zhuangfeng2(func): # 定义装饰器2
print("-----two---start")
def warper():
print("打麻椒..")
return func() # 返回原函数
print("end")
return warper
# 使用装饰器
@zhuangfeng2
@zhuangfeng1
def fz1():
return "户主一"
print(fz1())
"""
-----one---start
end
-----two---start
end
打麻椒..
刷漆..
户主一
"""
# 总结:多个装饰器作用于同一个函数的时候,从上往下依次执行,但是,原函数只被调用一次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 装饰器带有参数
需要定义三层函数
'''
装饰器带参数
带参数的装饰器是三层的
第一层: 负责接收装饰器的参数
第二层: 负责接收函数
第三层: 去接收函数里面的参数
'''
def outer(a): # 第一层: 负责接收装饰器的参数
def decorate(func): # 第二层: 负责接收函数
def wraper(*args, **kwargs): # 第三层: 复制接收函数的参数
func(*args, **kwargs)
print("--->铺地砖{}块".format(a))
return wraper
return decorate
@outer(100) # 装饰器带有参数
def house(time):
print("我{}日期拿到了毛坯房".format(time))
house("2020-9-9")
我2020-9-9日期拿到了毛坯房
--->铺地砖100块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def check_workflow_owner(view_func):
"""检查是否是workflow的创建者"""
def wrapper(request, *args, **kwargs):
if request.request.workflow_id: # 如果来自workflow通过验证
return view_func(request, *args, **kwargs)
user_id = request.request.id
is_owner = WorkFlow.objects.filter(id=kwargs.get('workflow_id'),
owner_id=user_id).exists()
if is_owner or is_master(kwargs.get('workspace_id'), user_id):
return view_func(request, *args, **kwargs)
else:
raise APIException('无法进行操作', code=stat.PermissionsError)
return wrapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 使用__call__方法定义装饰器
class A(object):
def __init__(self, func):
self.func = func
def __call__(self):
print('this is call')
return self.func() # 调用f这个函数
@A # 语法糖,相当于A(f)
def f():
print('hhh')
f() # 执行call方法
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
编辑 (opens new window)
上次更新: 2023/05/17, 23:08:21