这一节了解了一些装饰器的简单使用。
首先来看一个预备知识,把一个函数当做参数,传入另外一个函数
比如说我传递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
|