装饰器是一种特殊的函数,它可以在装饰其他函数或者类,使用装饰器可以在函数执行之前和执行之后添加相应的操作。看如下代码:
1
2
3
4
5
6
7
8
9
10
11
| #!/usr/bin/env python
# -*- coding:utf-8 -*-
① def f1(arg):④
arg()⑤
② def func(): ⑥
print '123'⑦
③ f1(func)
|
分析以上代码在解释器中的执行顺序:
代码开始运行时顺序是从上到下依次执行,第一、二步先将函数f1、func解释加载到内存中,其中函数中的内容arg()、print‘123’不执行,第三步(③)执行f1(func),当执行f1(func)时,就回到开始处,即第四步(④),找到函数f1,然后传入参数arg,其实的参数是函数func,所以将func函数载入到函数f1内,接着进入第五步,arg(),其实就是执行func()函数,即再回func函数,也就是第六步,而func函数的内部代码的动作是打印123,所以就执行打印操作,即执行第七步print‘123’
所以再接着看如下代码:
def auth(func):
def inner():
func()#原函数
return inner
假设函数f1为最原始的函数
def f1():
print 'f1'
所以auth认证函数调用f1过程实质如下
def auth(func):#func = f1 ===>func()<===>f1()
def inner():
print 'before'
func)#====>原函数
return inner
对auth(f1)进行变量赋值
ret = auth(f1) =def inner():
print 'before'
func() #f1 ==>原函数
将ret替换成f1
f1 = auth(f1) =def iner():
print 'before'
f1()
从上述整个过程来看,auth函数对函数f1的封装然后再把封装后的函数重新赋值到f1,即对被封装的函数名重新赋值
由于Python给我们提供了更便捷的方式,即@装饰器名字即可,所以以上的部分可以归纳成如下:
def auth(func):#func = f1 ===>func()<===>f1() def inner(): print 'before' func)#====>原函数 return inner
@auth #===============================>此处就是调用装饰器 def f1(): print 'f1'
对于装饰器记住如下两点:
(装饰器的功能简单的说就是函数加上Python的一个语法堂)
①装饰器是一个函数,执行装饰器函数
②装饰器对被装饰的函数名进行重新赋值
对以上的代码进行具体优化:
⒈不带参数的装饰器
[iyunv@Python day003]#vim basic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| #!/usr/bin/env python
#-*- coding:utf-8 -*-
def auth(arg):
def inner():
print "before"
arg()
print "after"
return inner
def f1():
print "这是测试函数f1"
def f2():
print "这是测试函数f2"
def f3():
print "这是测试函数f3"
def f4():
print "这是测试函数f4"
|
[iyunv@Python day003]vim index.py
1
2
3
4
| #!/usr/bin/env python
#-*- coding:utf-8 -*-
import basic
basic.f1()
|
运行index.py输出如下结果:
1
2
| [iyunv@Python day003]#python index.py
这是测试函数f1
|
修改basic.py代码为如下:
1
| [iyunv@Python day003]#vim basic.py
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| #!/usr/bin/env python
#-*- coding:utf-8 -*-
def auth(func):
def inner():
print "before"
arg()
print "after"
return inner
@auth
def f1():
print "这是测试函数f1"
def f2():
print "这是测试函数f2"
def f3():
print "这是测试函数f3"
@auth
def f4():
print "这是测试函数f4"
@auth
def f5():
print "这是测试函数f5"
|
1
| [iyunv@Python day003]#vim index.py
|
1
2
3
4
| #!/usr/bin/env python
#-*- coding:utf-8 -*-
import basic
basic.f1()
|
运行index.py查看结果:
1
| [iyunv@Python day003]#python index.py
|
1
2
3
| before
这是测试函数f1
after
|
⒉带固定参数的装饰器(arg)
basic脚本代码:
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
| #!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'ryan'
def auth(func):
def inner():
print "before"
func()
print "after"
return inner
def auth_arg(func):
def inner(arg):
print "before"
func(arg)
print "after"
return inner
@auth
def f1():
print "这是测试函数F1"
def f2():
print "这是测试函数F2"
def f3():
print "这是测试函数F3"
def f4():
print "这是测试函数F4"
@auth_arg
def f5(arg):
print "这是测试函数F5",arg
"""
@auth
def f1():
print "这是测试函数F1" ==============>相当于在执行函数auth(func),func函数体内的返回函数inner(),在返回inner函数时,先回到inner函数,进行执行inner函数体内的语句,即print "before" 、print "before"、func()等语句。其中func()就是原函数f1,而auth在整个函数都执行完之后就会返回一个值,然后将该值重新赋给原函数名f1,此时的函数f1功能已经发生变化,比之前未被auth调用之后多了输出"before"和"after"功能
"""
|
注:装饰器内层函数inner中的参数arg可以是n、m、x等字母、单词,不固定为某个字母或者单词,只是用它们做为一个标识符号,可以和原来函数f5(arg)中的参数相同,也可以不相同
index脚本代码:
1
2
3
4
5
6
7
| #!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'ryan'
import basic
basic.f1()
print "=========这里是分割线========"
basic.f5('1.1.1.1')
|
运行index.py脚本结果如下:
1
2
3
4
5
6
7
| before
这是测试函数F1
after
=========这里是分割线========
before
这是测试函数F5 1.1.1.1
after
|
3、带动态参数的装饰器(*arg,**kwargs)
basic.py代码如下:(修改的部分为内层函数inner带上参数*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
| #!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'ryan'
def auth(func):
def inner(*args,**kwargs):
print "before"
func(*args,**kwargs)
print "after"
return inner
@auth
def f1():
print "这是测试函数F1"
def f2():
print "这是测试函数F2"
def f3():
print "这是测试函数F3"
def f4():
print "这是测试函数F4"
@auth
def f5(arg):
print "这是测试函数F5",arg
|
index.py代码如下:(内容不作改动)
1
2
3
4
5
6
7
| #!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'ryan'
import basic
basic.f1()
print "=========这里是分割线========"
basic.f5('1.1.1.1')
|
运行(index.py)结果如下:
1
2
3
4
5
6
7
| before
这是测试函数F1
after
=========这里是分割线========
before
这是测试函数F5 1.1.1.1
after
|
4、含返回值的装饰器
basic.py脚本示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
| #!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'ryan'
def auth(func):
def inner(*args,**kwargs):
print "before"
func(*args,**kwargs)#这里的func函数就是原函数,这里就是fetch_server_list
print "after"
return inner
#@auth #===============================>不加装饰器时
def fetch_server_list(arg):
server_list=['host1','host2','host3']
return server_list
|
index.py代码如下:
1
2
3
4
5
6
| #!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'ryan'
import basic
ret_list =basic.fetch_server_list('host')
print ret_list
|
运行结果:
1
| ['host1', 'host2', 'host3']
|
发现拿到了主机名列表
下面添加装饰器,即将代码#@auth前的“#”注释去掉:
1
2
3
4
5
6
7
8
9
10
11
12
13
| #!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'ryan'
def auth(func):
def inner(*args,**kwargs):
print "before"
func(*args,**kwargs)#这里的func函数就是原函数,这里就是fetch_server_list
print "after"
return inner
@auth #===============================>增加装饰器时
def fetch_server_list(arg):
server_list=['host1','host2','host3']
return server_list
|
index.py代码如下:
1
2
3
4
5
6
| #!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'ryan'
import basic
ret_list =basic.fetch_server_list('host')
print ret_list
|
运行结果:
解释:执行index.py时,其实就是间接执行basic.py中的函数fetch_server_list(arg),但是因为fetch_server_list(arg)加载了装饰器,所以此时的fetch_server_list函数其实就是装饰器中的函数inner(*args,**kwargs),所以就执行inner(*,**kwargs)函数,即执行:
1
2
3
4
| def inner(*args,**kwargs):
print "before"
func(*args,**kwargs)#原fetch_server_list(arg)函数
print"after"
|
此时inner函数体中的func(*args,**kwargs)实质是没有加载装饰器之前的(原fetch_server_list函数)fetch_server_list(arg)函数,这里要与inner(*args,**kwargs)函数是fetch_server_list(arg)函数区分开来,即:一个是加载装饰器之后的(即新的fetch_server_list),一个是加载装饰器之前的(即原fetch_server_list).所以再回过来看输出结果,其中有一个None,None代表函数没有返回值,即函数没有返回值时候,默认返回None,没有返回值的函数如果将其赋值给某个变量,然后输出变量,得到的值就显示None,从inner函数体可以发现该函数是没有返回值的(即没有return 语句),
1
2
3
4
| def inner(*args,**kwargs):
print "before"
func(*args,**kwargs)#这里的func函数就是原函数fetch_server_list
print "after"
|
但是原函数体内有返回值(即return 语句),即有返回主机列表
1
2
3
| def fetch_server_list(arg):
server_list=['host1','host2','host3']
return server_list
|
这里将装饰器再做修改,代码如下:
basic.py代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| #!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'ryan'
def auth(func):
def inner(*args,**kwargs):
print "before"
temp = func(*args,**kwargs)#这里的func函数代表的就是原函数fetch_server_list
print "after"
return temp
return inner
@auth
def fetch_server_list(arg):
server_list=['host1','host2','host3']
return server_list
|
index.py代码:
1
2
3
4
5
6
| #!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'ryan'
import basic
ret =basic.fetch_server_list('host')
print ret
|
运行结果:
1
2
3
| before
after
['host1', 'host2', 'host3']
|
|