Python中decorator使用实例


Posted in Python onApril 14, 2015

在我以前介绍 Python 2.4 特性的Blog中已经介绍过了decorator了,不过,那时是照猫画虎,现在再仔细描述一下它的使用。

关于decorator的详细介绍在 Python 2.4中的What's new中已经有介绍,大家可以看一下。

如何调用decorator

基本上调用decorator有两种形式

第一种:

@A

def f ():

这种形式是decorator不带参数的写法。最终 Python 会处理为:

f = A(f)

还可以扩展成:
@A

@B

@C

def f ():

   

最终 Python 会处理为:

f = A(B(C(f)))

注:文档上写的是@A @B @C的形式,但实际上是不行的,要写成多行。而且执行顺序是按函数调用顺序来的,先最下面的C,然后是B,然后是A。因此,如果decorator有顺序话,一定要注意:先要执行的放在最下面,最后执行的放在最上面。(应该不存在这种倒序的关系)

第二种:

@A(args)

def f ():

   

这种形式是decorator带参数的写法。那么 Python 会处理为:

def f(): 

_deco = A(args)

f = _deco(f)

可以看出, Python 会先执行A(args)得到一个decorator函数,然后再按与第一种一样的方式进行处理。

decorator函数的定义

每一个decorator都对应有相应的函数,它要对后面的函数进行处理,要么返回原来的函数对象,要么返回一个新的函数对象。请注意,decorator只用来处理函数和类方法。

第一种:
针对于第一种调用形式

def A(func):

    #处理func

    #如func.attr='decorated'

    return func

@A

def f(args):pass

上面是对func处理后,仍返回原函数对象。这个decorator函数的参数为要处理的函数。如果要返回一个新的函数,可以为:

def A(func):

    def new_func(args):

        #做一些额外的工作

        return func(args) #调用原函数继续进行处理

    return new_func

@A

def f(args):pass

要注意 new_func的定义形式要与待处理的函数相同,因此还可以写得通用一些,如:

def A(func):

    def new_func(*args, **argkw):

        #做一些额外的工作

        return func(*args, **argkw) #调用原函数继续进行处理

    return new_func

@A

def f(args):pass

可以看出,在A中定义了新的函数,然后A返回这个新的函数。在新函数中,先处理一些事情,比如对参数进行检查,或做一些其它的工作,然后再调原始的函数进行处理。这种模式可以看成,在调用函数前,通过使用decorator技术,可以在调用函数之前进行了一些处理。如果你想在调用函数之后进行一些处理,或者再进一步,在调用函数之后,根据函数的返回值进行一些处理可以写成这样:

def A(func):

    def new_func(*args, **argkw):

        result = func(*args, **argkw) #调用原函数继续进行处理

        if result:

            #做一些额外的工作

            return new_result

        else:

            return result

    return new_func

@A

def f(args):pass

第二种:
针对第二种调用形式

在文档上说,如果你的decorator在调用时使用了参数,那么你的decorator函数只会使用这些参数进行调用,因此你需要返回一个新的decorator函数,这样就与第一种形式一致了。

def A(arg):

    def _A(func):

        def new_func(args):

            #做一些额外的工作

            return func(args)

        return new_func

    return _A

@A(arg)

def f(args):pass

可以看出A(arg)返回了一个新的 decorator _A。

decorator的应用场景

不过我也一直在想,到底decorator的魔力是什么?适合在哪些场合呢?是否我需要使用它呢?

decorator的魔力就是它可以对所修饰的函数进行加工。那么这种加工是在不改变原来函数代码的情况下进行的。有点象我知道那么一点点的AOP(面向方面编程)的想法。

它适合的场合我能想到的列举出下:

1.象文档中所说,最初是为了使调用staticmethod和classmethod这样的方法更方便
2.在某些函数执行前做一些工作,如web开发中,许多函数在调用前需要先检查一下用户是否已经登录,然后才能调用
3.在某此函数执行后做一些工作,如调用完毕后,根据返回状态写日志
4.做参数检查

可能还有许多,你可以自由发挥想象

那么我需要用它吗?

我想那要看你了。不过,我想在某些情况下,使用decorator可以增加程序的灵活性,减少耦合度。比如前面所说的用户登录检查。的确可以写一个通用的登录检查函数,然后在每个函数中进行调用。但这样会造成函数不够灵活,而且增加了与其它函数之间的结合程度。如果用户登录检查功能有所修改,比如返回值的判断发生了变化,有可能每个用到它的函数都要修改。而使用decorator不会造成这一问题。同时使用decorator的语法也使得代码简单,清晰(一但你熟悉它的语法的话)。当然你不使用它是可以的。不过,这种函数之间相互结合的方式,更符合搭积木的要求,它可以把函数功能进一步分解,使得功能足够简单和单一。然后再通过decorator的机制灵活的把相关的函数串成一个串,这么一想,还真是不错。比如下面:

@A

@B

def account(args):pass

假设这是一个记帐处理函数,account只管记帐。但一个真正的记帐还有一些判断和处理,比如:B检查帐户状态,A记日志。这样的效果其实是先检查B、通过在A中的处理可以先执行account,然后再进行记日志的处理。象搭积木一样很方便,改起来也容易。甚至可以把account也写成decorator,而下面执行的函数是一个空函数。然后再通过配置文件等方法,将decorator的组合保存起来,就基本实现功能的组装化。是不是非常理想。

Python 带给人的创造力真是无穷啊!

Python 相关文章推荐
python2.7的编码问题与解决方法
Oct 04 Python
python中将字典形式的数据循环插入Excel
Jan 16 Python
python3爬取淘宝信息代码分析
Feb 10 Python
Python任意字符串转16, 32, 64进制的方法
Jun 12 Python
pytorch多进程加速及代码优化方法
Aug 19 Python
django ajax发送post请求的两种方法
Jan 05 Python
使用Python三角函数公式计算三角形的夹角案例
Apr 15 Python
keras导入weights方式
Jun 12 Python
python属于解释型语言么
Jun 15 Python
python简单利用字典破解zip文件口令
Sep 07 Python
python实现b站直播自动发送弹幕功能
Feb 20 Python
Python的代理类实现,控制访问和修改属性的权限你都了解吗
Mar 21 Python
用Python创建声明性迷你语言的教程
Apr 13 #Python
Python中的Numeric包和Numarray包使用教程
Apr 13 #Python
Python中一些自然语言工具的使用的入门教程
Apr 13 #Python
用Python的SimPy库简化复杂的编程模型的介绍
Apr 13 #Python
Python中用Decorator来简化元编程的教程
Apr 13 #Python
在Python的setuptools框架下生成egg的教程
Apr 13 #Python
简单介绍Python中的RSS处理
Apr 13 #Python
You might like
PHP 分页原理分析,大家可以看看
2009/12/21 PHP
PHP多线程批量采集下载美女图片的实现代码(续)
2013/06/03 PHP
解决file_get_contents无法请求https连接的方法
2013/12/17 PHP
PHP设计模式之工厂方法设计模式实例分析
2018/04/25 PHP
PHP实现转盘抽奖算法分享
2020/04/15 PHP
PHP面向对象程序设计之接口的继承定义与用法详解
2018/12/20 PHP
PHP常用正则表达式精选(推荐)
2019/05/28 PHP
浅谈PHP5.6 与 PHP7.0 区别
2019/10/09 PHP
修改jQuery.Autocomplete插件 支持中文输入法 避免TAB、ENTER键失效、导致表单提交
2009/10/11 Javascript
不同浏览器的怪癖小结
2010/07/11 Javascript
jQuery中DOM树操作之复制元素的方法
2015/01/23 Javascript
深入理解JavaScript系列(18):面向对象编程之ECMAScript实现
2015/03/05 Javascript
javascript淘宝主图放大镜功能
2016/10/20 Javascript
详解JS中定时器setInterval和setTImeout的this指向问题
2017/01/06 Javascript
JavaScript下拉菜单功能实例代码
2017/03/01 Javascript
jQuery树插件zTree使用方法详解
2017/05/02 jQuery
jQuery实现滚动到底部时自动加载更多的方法示例
2018/02/18 jQuery
使用typescript开发angular模块并发布npm包
2018/04/19 Javascript
jquery传参及获取方式(两种方式)
2020/02/13 jQuery
javascript canvas检测小球碰撞
2020/04/17 Javascript
详解ES6中class的实现原理
2020/10/03 Javascript
[02:54]DOTA2英雄基础教程 暗影牧师戴泽
2013/12/05 DOTA
在Python中使用pngquant压缩png图片的教程
2015/04/09 Python
详细解读Python中的__init__()方法
2015/05/02 Python
机器学习的框架偏向于Python的13个原因
2017/12/07 Python
完美解决TensorFlow和Keras大数据量内存溢出的问题
2020/07/03 Python
使用python编写一个语音朗读闹钟功能的示例代码
2020/07/14 Python
最新PyCharm从安装到PyCharm永久激活再到PyCharm官方中文汉化详细教程
2020/11/17 Python
HTML5中判断横屏竖屏的方法(移动端)
2016/08/04 HTML / CSS
Unix控制后台进程都有哪些进程
2016/09/22 面试题
毕业生的自我评价范文
2013/12/31 职场文书
卫生厅领导班子党的群众路线教育实践活动整改措施
2014/09/20 职场文书
财务工作检讨书
2014/10/29 职场文书
2014大学生学生会工作总结
2014/12/19 职场文书
小学母亲节活动总结
2015/02/10 职场文书
pytorch 实现变分自动编码器的操作
2021/05/24 Python