深入理解Python装饰器


Posted in Python onJuly 27, 2016

装饰器简介:

装饰器(decorator)是一种高级Python语法。装饰器可以对一个函数、方法或者类进行加工。在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一个函数的返回结果。相对于其它方式,装饰器语法简单,代码可读性高。因此,装饰器在Python项目中有广泛的应用。

装饰器最早在Python 2.5中出现,它最初被用于加工函数和方法这样的可调用对象(callable object,这样的对象定义有__call__方法)。在Python 2.6以及之后的Python版本中,装饰器被进一步用于加工类。

装饰器主要是用来包装函数,对于一些常用的功能,譬如:日志打印,函数计时,身份认证。我们可以使用装饰器来实现,这样可以降低整个程序的复杂度和减少程序的代码量。

它实际上就是函数,不同的是,它把一个函数当做参数,然后返回一个替代版函数。

下面看一个简单的示例:

def add_number(func):
def adder(arg):
return func(arg)+100
return adder
def f(x):
return x
f=add_number(f)
print f(20)

add_number就是一个装饰器函数,它接受一个函数(f)作为参数,然后返回另外一个函数(adder)赋值给原来的函数,这样,原来的函数不用新添加额外的代码量而实现了加法的功能。

这个就是装饰器的原始实现。

But,这种方式还是有点不太方便,毕竟还是绕了一圈,用f=add_number(f)来给原来的函数重新赋值。

其实,Python中可以用下列方式来简化对于装饰器的引用。

def add_number(func):
def adder(arg):
return func(arg)+100
return adder
@add_number
def f(x):
return x
print f(20)

只需一个简单的@add_numbe调用,是不是方便,简单了很多,基本上没侵入原来的代码。

额,大家发现没有,作为装饰器,每次接受的参数无非两种:函数和函数的参数,但书写的格式基本一样,有没有办法来简化这种书写呢?

有,Python提供了一个decorator包,可以大大简化装饰器的书写。

So,第三种实现方式为:

from decorator import decorator
@decorator
def wrapper(func,arg):
return func(arg)+100
@wrapper
def f(x):
return x
print f(20)

喔,果然更加简单了~

以上示例接受的都是一个参数,其实,函数本身是可以接受可变参数的。

如:

@decorator
def wrapper(f,arg1,*args,**kwargs):
print "I am just a wrapper~"
return f(arg1,*args,**kwargs)
@wrapper
def f(arg1,*args,**kwargs):
print arg1
for eacheArg in args:
print 'non-keyword arg:',eacheArg
for eachKw in kwargs.keys():
print 'keyword arg: %s:%d' % (eachKw,kwargs[eachKw])
args=('Joy','Steve')
kwargs={"age":20}
f('China',*args,**kwargs)

输出结果为:

I am just a wrapper~
China
non-keyword arg: Joy
non-keyword arg: Steve
keyword arg: age:20

关于*args,**kwargs的区别,两者都可用于表示可变长度的参数。只不过前者是用元祖表示,没有key值,后者是字典,有key值。两者可用于在同一个函数中,但是,*args必须出现在**kwargs之前。

譬如下例:

def test_var_args_call(arg1, arg2, arg3):
print "arg1:", arg1
print "arg2:", arg2
print "arg3:", arg3
args=(1,2,3)
kwargs ={"arg1":"1","arg3": 3, "arg2": "2"}
test_var_args_call(*args)
print '-----------------'
test_var_args_call(**kwargs)

两者的实现效果一样。

最后来个示例,通过显示函数执行的时间来装饰一个函数

import time
def log(func):
def wrapper(*args, **kw):
print '[%s] %s() was called...' % (time.ctime(),func.__name__)
return func(*args, **kw)
return wrapper
@log
def foo():
pass
for i in range(4):
foo()
time.sleep(1)

输出结果如下:

[Wed Jul 27 09:17:23 2016] foo() was called...
[Wed Jul 27 09:17:24 2016] foo() was called...
[Wed Jul 27 09:17:25 2016] foo() was called...
[Wed Jul 27 09:17:26 2016] foo() was called...

以上所述是小编给大家介绍的深入理解Python装饰器,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
讲解Python中运算符使用时的优先级
May 14 Python
详解Python的Django框架中inclusion_tag的使用
Jul 21 Python
python 实现tar文件压缩解压的实例详解
Aug 20 Python
python基础_文件操作实现全文或单行替换的方法
Sep 04 Python
python+matplotlib绘制简单的海豚(顶点和节点的操作)
Jan 02 Python
Python进阶之@property动态属性的实现
Apr 01 Python
Tensorflow获取张量Tensor的具体维数实例
Jan 19 Python
Python实现获取当前目录下文件名代码详解
Mar 10 Python
浅谈tensorflow 中的图片读取和裁剪方式
Jun 30 Python
Python趣味实例,实现一个简单的抽奖刮刮卡
Jul 18 Python
Python编写万花尺图案实例
Jan 03 Python
python实现图片转字符画的完整代码
Feb 21 Python
python批量制作雷达图的实现方法
Jul 26 #Python
python 添加用户设置密码并发邮件给root用户
Jul 25 #Python
Python文件夹与文件的相关操作(推荐)
Jul 25 #Python
浅谈python类属性的访问、设置和删除方法
Jul 25 #Python
python直接访问私有属性的简单方法
Jul 25 #Python
python类:class创建、数据方法属性及访问控制详解
Jul 25 #Python
python实现汉诺塔方法汇总
Jul 25 #Python
You might like
php使用sql数据库 获取字段问题介绍
2013/08/12 PHP
php获取图片信息的方法详解
2015/12/10 PHP
Laravel实现表单提交
2017/05/07 PHP
在 IE 中调用 javascript 打开 Excel 表
2006/12/21 Javascript
JavaScript 定义function的三种方式小结
2009/10/16 Javascript
腾讯与新浪的通过IP地址获取当前地理位置(省份)的接口
2010/07/26 Javascript
javascript中callee与caller的用法和应用场景
2010/12/08 Javascript
javascript开发随笔二 动态加载js和文件
2011/11/25 Javascript
jQuery 下拉列表 二级联动插件分享
2012/03/29 Javascript
jquery根据name属性查找的小例子
2013/11/21 Javascript
js如何调用qq互联api实现第三方登录
2014/03/28 Javascript
JSON.stringify转换JSON时日期时间不准确的解决方法
2014/08/08 Javascript
JQuery插件Quicksand实现超炫的动画洗牌效果
2015/05/03 Javascript
jQuery实现在列表的首行添加数据
2015/05/19 Javascript
使用微信内置浏览器点击下拉框出现页面乱跳转现象(iphone),该怎么办
2016/01/04 Javascript
js创建对象几种方式的优缺点对比
2016/09/28 Javascript
基于Bootstrap仿淘宝分页控件实现代码
2016/11/07 Javascript
vue2.0+webpack环境的构造过程
2016/11/08 Javascript
网站发布后Bootstrap框架引用woff字体无法正常显示的解决方法
2016/11/24 Javascript
利用node实现一个批量重命名文件的函数
2017/12/21 Javascript
vue利用axios来完成数据的交互
2018/03/23 Javascript
Vue前后端不同端口的实现方法
2018/09/19 Javascript
Node.js 多进程处理CPU密集任务的实现
2019/05/26 Javascript
python基于ID3思想的决策树
2018/01/03 Python
pandas按若干个列的组合条件筛选数据的方法
2018/04/11 Python
对python 操作solr索引数据的实例详解
2018/12/07 Python
Python实现元素等待代码实例
2019/11/11 Python
使用Python matplotlib作图时,设置横纵坐标轴数值以百分比(%)显示
2020/05/16 Python
CSS的pointer-events属性详细介绍(作用和注意事项)
2014/04/23 HTML / CSS
Adobe Html5 Extension开发初体验图文教程
2017/11/14 HTML / CSS
Shop Apotheke瑞士:您的健康与美容网上商店
2019/10/09 全球购物
Pottery Barn阿联酋:购买家具、家居装饰及更多
2019/12/08 全球购物
幼教毕业生自我鉴定
2014/01/12 职场文书
社区戒毒工作方案
2014/06/04 职场文书
慰问信格式规范
2015/03/23 职场文书
2019个人工作计划书的格式及范文!
2019/07/04 职场文书