装饰器
讲装饰器之前要先了解两个概念:
- 对象引用 :对象名仅仅只是个绑定内存地址的变量
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