这一节了解了一些装饰器的简单使用。
首先来看一个预备知识,把一个函数当做参数,传入另外一个函数
比如说我传递outer(f1),我传入的是f1的内存地址,a=func()其实执行了f1()这个函数,并把返回值赋给了a,因此当我打印print(a),他会输出hee
1
2
3
4
5
6
7
8
9
10
11
12
|
>>>
def
outer(func):
print
(func)
a
=
func()
print
(a)
def
f1():
print
(
"aaa"
)
return
"hee"
outer(f1)
-
-
-
-
-
-
-
-
-
-
-
-
<function f1 at
0x0000023D3FF3D510
>
aaa
hee
|
装饰器(decorator)就是利用可以把函数当做传递这一点,他可以统一给一些函数添加一些“修饰”功能,但是又不会去破坏原有的代码。装饰器本身也是一个函数,其他函数调用他的时候,在其他函数前面 @ +装饰器名的格式就行了
这个格式执行了2个功能:
1. 自动执行装饰器函数并且将其下面的函数名f1当作参数传递
2. 将装饰器函数的返回值,重复赋值给 f1
简单的说就是这样
f1=decortor(f1)
把上面的例子稍微修改成装饰器,如下所示,结果是一样的
1
2
3
4
5
6
7
8
9
10
11
12
|
def
outer(func):
def
innner(
*
args,
*
*
kwargs):
print
(func)
a
=
func(
*
args,
*
*
kwargs)
print
(a)
return
a
return
innner
@outer
def
f1():
print
(
"aaa"
)
return
"hee"
f1()
|
再看另外一个复杂一些的例子:
我定义了3个函数f1,f2,f3,他们有不同的参数,我需要每个函数在现在的结果前面添加一个'before',结果后面添加一个‘after’
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
|
def
outer(func):
def
inner(
*
args,
*
*
kwargs):
print
(
'before'
)
r
=
func(
*
args,
*
*
kwargs)
print
(
'after'
)
return
r
return
inner
@outer
def
f1(arg):
print
(arg)
return
"F1"
@outer
def
f2(a1, a2):
print
(
"F2"
)
@outer
def
f3():
print
(
"F3"
)
f1(
"hhh"
)
f2(
"bbb"
,
444
)
f3()
|
结果如下:
1
2
3
4
5
6
7
8
9
|
before
hhh
after
before
F2
after
before
F3
after
|
注意要点:
当使用装饰器outer的时候,他传递参数 outer(f1),这里传递的是f1的地址;r=func()其实执行的就是f1(),然后把返回值赋给了r,这里的目的是为了保证inner返回的结果和f1返回的结果一样;最后再把装饰过的inner函数地址赋给f1,实现装饰的效果;
记得前面的万能参数 f(*args,**kwargs),可以接受任意的参数
例2:装饰器一个广泛使用的场景是登录验证;很多功能必须判断登录之后才能使用。
下面的例子装饰器通过一个全局变量LOGIN_USER来判断是否已经登录。
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
|
#!/usr/bin/env python
# -*- coding:utf-8 -*-
LOGIN_USER
=
{
"is_login"
:
False
}
def
outer(func):
def
inner(
*
args,
*
*
kwargs):
if
LOGIN_USER[
'is_login'
]:
r
=
func()
return
r
else
:
print
(
"请登录"
)
return
inner
def
outer1(func):
def
inner(
*
args,
*
*
kwargs):
if
LOGIN_USER[
'is_login'
]
and
LOGIN_USER[
'user_type'
]
=
=
2
:
r
=
func()
return
r
else
:
print
(
"请登录,或者权限不够"
)
return
inner
@outer1
def
order():
print
(
"欢迎%s登录"
%
LOGIN_USER[
'current_user'
])
@outer
def
changepwd():
print
(
"欢迎%s登录"
%
LOGIN_USER[
'current_user'
])
@outer
def
manager():
print
(
"欢迎%s登录"
%
LOGIN_USER[
'current_user'
])
def
login(user, pwd):
if
user
=
=
"alex"
and
pwd
=
=
"123"
:
LOGIN_USER[
'is_login'
]
=
True
LOGIN_USER[
'current_user'
]
=
user
manager()
def
main():
while
True
:
inp
=
input
(
"1,后台管理;2,登录"
)
if
inp
=
=
'1'
:
manager()
elif
inp
=
=
'2'
:
username
=
input
(
"请输入用户名"
)
pwd
=
input
(
"请输入密码"
)
login(username, pwd)
main()
|
例3.
如果有多个装饰器,我可以嵌套的使用,因为一层的装饰器之后其实也是一个函数,那他自然可以再继续被装饰。
比如说,注意他的调用顺序是从下往上的
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
|
Python
3.5
.
2
(v3.
5.2
:
4def2a2901a5
, Jun
25
2016
,
22
:
18
:
55
) [MSC v.
1900
64
bit (AMD64)] on win32
>>>
def
outer(func):
def
innner(
*
args,
*
*
kwargs):
print
(func)
a
=
func(
*
args,
*
*
kwargs)
print
(
"装饰1"
)
return
a
return
innner
def
outer2(func):
def
inner(
*
args,
*
*
kwargs):
print
(func)
a
=
func(
*
args,
*
*
kwargs)
print
(
"装饰2"
)
return
a
return
inner
@outer2
@outer
def
f1():
print
(
"原函数"
)
return
"hee"
f1()
<function outer.<
locals
>.innner at
0x000001FF89A6D620
>
<function f1 at
0x000001FF89A6D598
>
原函数
装饰
1
装饰
2
|