深入理解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 相关文章推荐
在MAC上搭建python数据分析开发环境
Jan 26 Python
在阿里云服务器上配置CentOS+Nginx+Python+Flask环境
Jun 18 Python
深入理解Python中的内置常量
May 20 Python
Python用户推荐系统曼哈顿算法实现完整代码
Dec 01 Python
windows下Virtualenvwrapper安装教程
Dec 13 Python
python代码实现ID3决策树算法
Dec 20 Python
python的socket编程入门
Jan 29 Python
在python3.5中使用OpenCV的实例讲解
Apr 02 Python
深入浅析python 协程与go协程的区别
May 09 Python
python按行读取文件并找出其中指定字符串
Aug 08 Python
Python标准库shutil模块使用方法解析
Mar 10 Python
Python如何在循环内使用list.remove()
Jun 01 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&mysql(六)
2006/10/09 PHP
php auth_http类库进行身份效验
2009/03/19 PHP
php计算指定目录下文件占用空间的方法
2015/03/13 PHP
PHP生成各种常见验证码和Ajax验证过程
2016/01/10 PHP
PHP7.1方括号数组符号多值复制及指定键值赋值用法分析
2016/09/26 PHP
thinkphp框架使用JWTtoken的方法详解
2019/10/10 PHP
jQuery学习总结之元素的相对定位和选择器(持续更新)
2011/04/26 Javascript
Javascript拓展String方法小结
2013/07/08 Javascript
jQuery实现文件上传进度条特效
2015/08/12 Javascript
jQuery实现Flash效果上下翻动的中英文导航菜单代码
2015/09/22 Javascript
浅析$.getJSON异步请求和同步请求
2016/06/06 Javascript
基于jQuery实现Accordion手风琴自定义插件
2020/10/13 Javascript
基于匀速运动的实例讲解(侧边栏,淡入淡出)
2017/10/17 Javascript
vue keep-alive请求数据的方法示例
2018/05/16 Javascript
jQuery内容过滤选择器与子元素过滤选择器用法实例分析
2019/02/20 jQuery
详释JavaScript执行环境与执行栈
2019/04/02 Javascript
如何写好一个vue组件,老夫的一年经验全在这了(推荐)
2019/05/18 Javascript
vue中datepicker的使用教程实例代码详解
2019/07/08 Javascript
vue动态子组件的两种实现方式
2019/09/01 Javascript
uni-app从安装到卸载的入门教程
2020/05/15 Javascript
Python简单实现Base64编码和解码的方法
2017/04/29 Python
python2 中 unicode 和 str 之间的转换及与python3 str 的区别
2019/07/25 Python
使用Python和OpenCV检测图像中的物体并将物体裁剪下来
2019/10/30 Python
Python3内置函数chr和ord实现进制转换
2020/06/05 Python
使用Python操作MySQL的小技巧
2020/09/10 Python
python 基于opencv 绘制图像轮廓
2020/12/11 Python
python实现发送QQ邮件(可加附件)
2020/12/23 Python
详解px单位html5响应式方案
2018/03/08 HTML / CSS
会计毕业生求职简历的自我评价
2013/10/20 职场文书
车间操作工岗位职责
2013/12/19 职场文书
毕业生简历自我评价范文
2014/04/09 职场文书
学校党支部公开承诺书
2015/04/30 职场文书
起诉书格式范文
2015/05/20 职场文书
公司车队管理制度
2015/08/04 职场文书
六年级作文之关于梦
2019/10/22 职场文书
php7中停止php-fpm服务的方法详解
2021/05/09 PHP