Python 装饰器
发布日期:2021-08-15 09:33:45 浏览次数:15 分类:技术文章

本文共 4089 字,大约阅读时间需要 13 分钟。

装饰器示例

def w1(func):    def inner():        print('...验证权限...')        func()    return inner@w1def f1():    print('f1 called')f1()

输出结果

1 ...验证权限...2 f1 called

装饰器原理

  首先,函数 w1(func) 是一个装饰器,该函数有个参数 func,用来接收一个方法;w1 内部又定义了一个函数 inner() ,

执行完 print 之后,调用传进来的函数,然后返回值为内部函数 inner(),这就是 “闭包” 函数。

  然后,在 f1 上面的@w1 ,相当于 f1 = w1( f1 ),对其做了简化;此时的 f1 指向了 w1.inner 函数的地址。

两个装饰器执行流程

def makeBold(fun):    print('----a----')    def inner():        print('----1----')        return '' + fun() + ''    return innerdef makeItalic(fun):    print('----b----')    def inner():        print('----2----')        return '' + fun() + ''    return inner@makeBold@makeItalicdef test():    print('----c----')    print('----3----')    return 'hello python decorator'ret = test()print(ret)

执行结果

1 ----b----2 ----a----3 ----1----4 ----2----5 ----c----6 ----3----7 hello python decorator

  首先 test() 先被第二个装饰器(makeItalic)装饰,接着被第一个装饰器(makeBold);而调用过程中,先执行第一个装饰器(makeBold),

然后再执行第二个装饰器(makeItalic)。

接着我们来仔细分析一下:

  1、装饰器只对函数进行装饰,不对装饰器装饰。所以在执行@makeBold的时候,遇到另一个装饰器暂停执行;接下来执行@makeItalic,把 test 函数传入

装饰器,从而打印 'b' ,在makeItalic装饰完后,此时 test 指向 makeItalic 的 inner 函数地址;然后 返回来执行 @makeBold ,接着把 新的 test 传入 makeBold

装饰器,因此打印了 'a' 。    

   2、第一次装饰 test = makeItalic( test ),第二次 装饰 test = makeBold( makeItalic( test ) )。经过分析,此时应该先执行 makeBold. inner 函数,因此先打

印 '1',接下来再调用 makeBold. inner 函数里的 fun,其实就是makeItalic. inner 函数,所以打印 '2',在makeItalic. inner 中调用 fun ,其实就是最原始的 test(),

所以打印 test 函数的 'c','3',最后一层层返回,打印的结果就是 <b><i>hello python decorator</i></b>。

对有参函数进行装饰

 指定参数

def w_say(fun):    """    如果原函数有参数,那闭包函数必须保持参数个数一致,并且将参数传递给原方法    """    def inner(name):        """        如果被装饰的函数有行参,那么闭包函数必须有参数        """        print('say inner called')        fun(name)    return inner@w_saydef hello(name):    print('hello ' + name)hello('wangcai')

执行结果

1 say inner called2 hello wangcai

上述代码只能装饰指定参数的函数,下面代码就介绍了如何处理不定长参数

def w_add(func):    def inner(*args, **kwargs):        print('add inner called')        func(*args, **kwargs)    return inner@w_adddef add(a, b):    print('%d + %d = %d' % (a, b, a + b))@w_adddef add2(a, b, c):    print('%d + %d + %d = %d' % (a, b, c, a + b + c))add(2, 4)add2(2, 4, 6)

执行结果

1 add inner called2 2 + 4 = 63 add inner called4 2 + 4 + 6 = 12

利用python的可变参数轻松实现装饰带参数的函数。

 对带返回值的函数进行装饰

 下面对有返回值的函数进行装饰,按照之前的写法,代码是这样的

def w_test(func):    def inner():        print('w_test inner called start')        func()        print('w_test inner called end')    return inner@w_testdef test():    print('this is test fun')    return 'hello'ret = test()print('ret value is %s' % ret)

执行结果

1 w_test inner called start2 this is test fun3 w_test inner called end4 ret value is None

从执行结果来看,没有输出 test 函数 'hello',而是 'None';这是因为在 inner 函数中对 test 进行了调用,但没有接收返回值,也没进行返回,所以就是 None。

那么我们修改一下代码

def w_test(func):    def inner():        print('w_test inner called start')        str = func()        print('w_test inner called end')        return str    return inner@w_testdef test():    print('this is test fun')    return 'hello'ret = test()print('ret value is %s' % ret)

执行结果

1 w_test inner called start2 this is test fun3 w_test inner called end4 ret value is hello

带参数的装饰器

def func_args(pre='xiaoqiang'):    def w_test_log(func):        def inner():            print('...记录日志...visitor is %s' % pre)            func()        return inner    return w_test_log# 带有参数的装饰器能够起到在运行时,有不同的功能# 先执行func_args('wangcai'),返回w_test_log函数的引用# @w_test_log# 使用@w_test_log对test_log进行装饰@func_args('wangcai')def test_log():    print('this is test log')test_log()

执行结果

1 ...记录日志...visitor is wangcai2 this is test log

通过上述代码知道,带参数的装饰器就是在原闭包的基础上又加了一层了闭包。

和两层嵌套相比,三层嵌套执行效果是这样的

test_log = func_args('wangcai')(test_log)

通用装饰器

万能装饰器

def w_test(func):    def inner(*args, **kwargs):        ret = func(*args, **kwargs)        return ret    return inner@w_testdef test():    print('test called')@w_testdef test1():    print('test1 called')    return 'python'@w_testdef test2(a):    print('test2 called and value is %d ' % a)test()test1()test2(9)

执行结果

1 test called2 test1 called3 test2 called and value is 9

类装饰器

 

 

 

 

 

 

 

 

 

 

 

 

                       

 

转载于:https://www.cnblogs.com/Rain2017/p/9944380.html

转载地址:https://blog.csdn.net/weixin_30757793/article/details/99567981 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:枚举进阶
下一篇:myeclipse中的classpath

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年03月22日 11时55分27秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

matlab里inline定义矩阵,Matlab中的inline函数_matlab中inline函数 2019-04-21
php html标签自定义属性,浅谈JS读取DOM对象(标签)的自定义属性 2019-04-21
如何使用matlab的siso,利用Matlab内建程式SISODesignTool完成系统分析(Matlab61)开启.PDF... 2019-04-21
php 实现 model层,Thinkhphp5控制器调用的Model层的方法总结 2019-04-21
matlab6.0序列号,MFC软件获取USB设备的制造商、产品、序列号 2019-04-21
matlab中多边形滤波器,几种常见空间滤波器MATLAB实现 2019-04-21
matlab fminimax 例子,Matlab应用实例(8)—fminimax 2019-04-21
php://filter利用条件,浅谈php://filter技巧 2019-04-21
mplayer-php,mplayer+smplayer 前后端播放器安装 2019-04-21
oracle昨日时间,。。今日,昨日,上周,本月,本年,按时间统计总金额 2019-04-21
php验证卡号,PHP验证信用卡卡号是否正确函数 2019-04-21
mpvue微信小程序动画_推荐两个微信小程序开发框架 2019-04-21
固态硬盘分为哪几种_零基础玩转固态硬盘 深度排雷 买SSD掌握这些就够了 2019-04-21
调python返回图片_Python异常处理,3个好习惯分享给你 2019-04-21
15拆解_收藏:15款劲芯微芯片无线充产品拆解 2019-04-21
弹出u盘_都说:U盘直接拔出不会丢失文件,“安全弹出”形同虚设,对吗? 2019-04-21
怎么查看elementui版本_2021新年 Vue3.0 + Element UI 尝鲜小记 2019-04-21
adreno630gpu参数_小米8搭载Adreno 630图形处理器 比荣耀play上的GPU Turbo更成熟 2019-04-21
带bitlocker解密的pe_如何在PE下解锁bitlocker 2019-04-21
lj245a引脚功能图_谁找到74254,74LS245芯片引脚的功能和功能图啊? 2019-04-21