装饰器
讲装饰器之前要先了解两个概念:
- 对象引用 :对象名仅仅只是个绑定内存地址的变量
1
2
3
4
5
6
7
8
9
|
def func(): # 函数名仅仅只是个绑定内存地址的变量 print ( "i`m running" ) # 这是调用 func() # i`m running # 这是对象引用,引用的是内存地址 func2 = func print (func2 is func) # True # 通过引用进行调用 func2() # i`m running |
-
闭包:定义一个函数A,然后在该函数内部再定义一个函数B,并且B函数用到了外边A函数的变量
123456789
def
out_func():
out_a
=
10
def
inner_func(inner_x):
return
out_a
+
inner_x
return
inner_func
out
=
out_func()
print
(out)
# <function out_func.<locals>.inner_func at 0x7ff378af5c10> out_func返回的是inner_func的内存地址
print
(out(inner_x
=
2
))
# 12
装饰器和闭包不同点在于:装饰器的入参是函数对象,闭包入参是普通数据对象
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
|
def decorator_get_function_name(func): """ 获取正在运行函数名 :return: """ def wrapper( * arg): """ wrapper :param arg: :return: """ print (f "当前运行方法名:{func.__name__} with params: {arg}" ) return func( * arg) return wrapper @decorator_get_function_name def test_func_add(x, y): print (x + y) @decorator_get_function_name def test_func_sub(x, y): print (x - y) test_func_add( 1 , 2 ) # 当前运行方法名:test_func_add with params: (1, 2) # 3 test_func_sub( 3 , 5 ) # 当前运行方法名:test_func_sub with params: (3, 5) # -2 |
常用于如鉴权校验,例如笔者会用于登陆校验:
1
2
3
4
5
6
7
8
9
|
def login_check(func): def wrapper(request, * args, * * kwargs): if not request.session.get( 'login_status' ): return HttpResponseRedirect( '/api/login/' ) return func(request, * args, * * kwargs) return wrapper @login_check def edit_config(): pass |
装饰器内部的执行逻辑:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
""" > 1. def login_check(func): ==>将login_check函数加载到内存 > .... > @login_check ==>此处已经在内存中将login_check这个函数执行了!;并不需要等edit_config()实例化调用 > 2. 上例@login_check内部会执行以下操作: > 2.1 执行login_check函数,并将 @login_check 下面的 函数(edit_config) 作为login_check函数的参数,即:@login_check 等价于 login_check(edit_config) > 2.2 内部就会去执行: def wrapper(*args): # 校验session... return func(request, *args, **kwargs) # func是参数,此时 func 等于 edit_config,此处相当于edit_config(request, *args, **kwargs) return wrapper # 返回的 wrapper,wrapper代表的是函数对象,非函数实例化对象 2.3 其实就是将原来的 edit_config 函数塞进另外一个函数中,另一个函数当中可以做一些操作;再执行edit_config 2.4 将执行完的 login_check 函数返回值(也就是 wrapper对象)将此返回值再重新赋值给新 edit_config,即: 2.5 新edit_config = def wrapper: # 校验session... return 原来edit_config(request, *args, **kwargs) > 3. 也就是新edit_config()=login_check(edit_config):wrapper(request, *args, **kwargs):return edit_config(request, *args, **kwargs) 有点绕,大家看步骤细细理解。 """ |
同样一个函数也可以使用多个装饰器进行装饰,执行顺序从上到下
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
|
from functools import wraps def w1(func): @wraps (func) def wrapper( * args, * * kwargs): print ( "这里是第一个校验" ) return func( * args, * * kwargs) return wrapper def w2(func): @wraps (func) def wrapper( * args, * * kwargs): print ( "这里是第二个校验" ) return func( * args, * * kwargs) return wrapper def w3(func): def wrapper( * args, * * kwargs): print ( "这里是第三个校验" ) return func( * args, * * kwargs) return wrapper @w2 # 这里其实是w2(w1(f1)) @w1 # 这里是w1(f1) def f1(): print (f "i`m f1, at {f1}" ) @w3 def f2(): print (f "i`m f2, at {f2}" ) # ====================== 实例化阶段 ===================== f1() # 这里是第二个校验 # 这里是第一个校验 # i`m f1, at <function f1 at 0x7febc52f5e50> f2() # 这里是第三个校验 # i`m f2, at <function w3.<lo |
有同学可能要好奇 为什么f1对象打印的是“<function f1 at 0x7febc52f5e50>”,f2对象打印的是“<function w3..wrapper at 0x7febc52f5f70>”(也就是步骤2.5造成的,赋的值是wrapper对象),这就跟w1和w2 内部wrapper使用的wraps装饰器有关系了。
wraps的作用是:被修饰的函数(也就是里面的func)的一些属性值赋值给修饰器函数(wrapper)包括元信息和“函数对象”等。
同时装饰器也可以接受参数:
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
def decorator_get_function_duration(enable): """ :param enable: 是否需要统计函数执行耗时 :return: """ print ( "this is decorator_get_function_duration" ) def inner(func): print ( 'this is inner in decorator_get_function_duration' ) @wraps (func) def wrapper( * args, * * kwargs): print ( 'this is a wrapper in decorator_get_function_duration.inner' ) if enable: start = time.time() print (f "函数执行前:{start}" ) result = func( * args, * * kwargs) print ( '[%s]`s enable was %s it`s duration : %.3f s ' % (func.__name__, enable, time.time() - start)) else : result = func( * args, * * kwargs) return result return wrapper return inner def decorator_1(func): print ( 'this is decorator_1' ) @wraps (func) def wrapper( * args, * * kwargs): print ( 'this is a wrapper in decorator_1' ) return func( * args, * * kwargs) return wrapper def decorator_2(func): print ( 'this is decorator_2' ) @wraps (func) def wrapper( * args, * * kwargs): print ( 'this is a wrapper in decorator_2' ) return func( * args, * * kwargs) return wrapper @decorator_1 # 此处相当:decorator_1(decorator_2(decorator_get_function_duration(enable=True)(fun))) @decorator_2 # = decorator_2(decorator_get_function_duration(enable=True)(fun)) @decorator_get_function_duration (enable = True ) # = decorator_get_function_duration(enable=True)(fun) def fun(): time.sleep( 2 ) print ( "fun 执行完了~" ) fun() # ======== enable=False ============ """ this is decorator_get_function_duration this is inner in decorator_get_function_duration this is decorator_2 this is decorator_1 this is a wrapper in decorator_1 this is a wrapper in decorator_2 this is a wrapper in decorator_get_function_duration.inner fun 执行完了~ """ # ======== enable=True ============ """ this is decorator_get_function_duration this is inner in decorator_get_function_duration this is decorator_2 this is decorator_1 this is a wrapper in decorator_1 this is a wrapper in decorator_2 this is a wrapper in decorator_get_function_duration.inner 函数执行前:1634635708.648994 fun 执行完了~ [fun]`s enable was True it`s duration : 2.002 s """ |
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注服务器之家的更多内容!
原文链接:https://blog.csdn.net/weixin_45005677/article/details/120707139