设为首页 收藏本站
查看: 672|回复: 0

[经验分享] Python之装饰器

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2015-12-24 09:33:06 | 显示全部楼层 |阅读模式
装饰器是一种特殊的函数,它可以在装饰其他函数或者类,使用装饰器可以在函数执行之前和执行之后添加相应的操作。看如下代码:
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



运行结果:
1
2
3
before
after
None



解释:执行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']



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-155560-1-1.html 上篇帖子: 【Python】长字符串 换行 下篇帖子: python获取window下网卡流量的函数
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表