深入理解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构建Hopfield网络的教程
Apr 14 Python
python下如何查询CS反恐精英的服务器信息
Jan 17 Python
完美解决python3.7 pip升级 拒绝访问问题
Jul 12 Python
简单易懂Pytorch实战实例VGG深度网络
Aug 27 Python
Python3离线安装Requests模块问题
Oct 13 Python
pygame实现打字游戏
Feb 19 Python
python同义词替换的实现(jieba分词)
Jan 21 Python
详谈tensorflow gfile文件的用法
Feb 05 Python
TensorBoard 计算图的可视化实现
Feb 15 Python
彻底搞懂 python 中文乱码问题(深入分析)
Feb 28 Python
python 轮询执行某函数的2种方式
May 03 Python
一文读懂python Scrapy爬虫框架
Feb 24 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学习笔记之数组篇
2011/06/28 PHP
极酷的javascirpt,让你随意编辑任何网页
2007/02/25 Javascript
jquery.cvtooltip.js 基于jquery的气泡提示插件
2010/11/19 Javascript
js工具方法弹出蒙版
2013/05/08 Javascript
javascript内存管理详细解析
2013/11/11 Javascript
实用框架(iframe)操作代码
2014/10/23 Javascript
js中javascript:void(0) 真正含义
2020/11/05 Javascript
jquery zTree异步加载简单实例讲解
2016/02/25 Javascript
3kb jQuery代码搞定各种树形选择的实现方法
2016/06/10 Javascript
AngularJS入门教程之 XMLHttpRequest实例讲解
2016/07/27 Javascript
jquery鼠标悬停导航下划线滑出效果
2017/09/29 jQuery
vue实现裁切图片同时实现放大、缩小、旋转功能
2018/03/02 Javascript
element-ui表格列金额显示两位小数的方法
2018/08/24 Javascript
Vue实现数据请求拦截
2019/10/23 Javascript
浅谈Vue2.4.0 $attrs与inheritAttrs的具体使用
2020/03/08 Javascript
[04:09]2014DOTA2国际邀请赛Ti西雅图 历届冠军相继出局 BBC综述今日比赛
2014/07/20 DOTA
[01:03:59]2018DOTA2亚洲邀请赛3月30日 小组赛B组VGJ.T VS Secret
2018/03/31 DOTA
[01:11:32]VG vs FNATIC 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
Python2与Python3的区别实例总结
2019/04/17 Python
python 爬取学信网登录页面的例子
2019/08/13 Python
基于python实现微信好友数据分析(简单)
2020/02/16 Python
Python全局变量与global关键字常见错误解决方案
2020/10/05 Python
canvas绘制视频封面的方法
2018/02/05 HTML / CSS
Silk’n激光脱毛器官网:silkn.com
2016/10/06 全球购物
小学生安全保证书
2014/02/01 职场文书
如何写自我鉴定
2014/03/19 职场文书
青春励志演讲稿
2014/04/29 职场文书
爱心捐书活动总结
2014/07/05 职场文书
官僚主义现象查摆问题整改措施
2014/10/04 职场文书
贷款担保书
2015/01/20 职场文书
隐形的翅膀观后感
2015/06/10 职场文书
严以修身专题学习研讨会发言材料
2015/11/09 职场文书
2016党员干部廉洁自律心得体会
2016/01/13 职场文书
婚礼必备主持词范本!
2019/07/23 职场文书
Windows11里微软已经将驱动程序安装位置A盘删除
2021/11/21 数码科技
python语言中pandas字符串分割str.split()函数
2022/08/05 Python