深入理解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 字符串大小写转换的简单实例
Jan 21 Python
python的socket编程入门
Jan 29 Python
python项目对接钉钉SDK的实现
Jul 15 Python
python mqtt 客户端的实现代码实例
Sep 25 Python
pycharm通过ssh连接远程服务器教程
Feb 12 Python
pytorch实现CNN卷积神经网络
Feb 19 Python
Jupyter Notebook折叠输出的内容实例
Apr 22 Python
基于pandas向csv添加新的行和列
May 25 Python
Python内存泄漏和内存溢出的解决方案
Sep 26 Python
python实现双人五子棋(终端版)
Dec 30 Python
python 批量压缩图片的脚本
Jun 02 Python
python的html标准库
Apr 29 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中通过Ajax如何实现异步文件上传的代码实例
2011/05/07 PHP
开源php中文分词系统SCWS安装和使用实例
2014/04/11 PHP
用PHP和Shell写Hadoop的MapReduce程序
2014/04/15 PHP
php实现计算百度地图坐标之间距离的方法
2016/05/05 PHP
Adnroid 微信内置浏览器清除缓存
2016/07/11 PHP
php并发加锁问题分析与设计代码实例讲解
2021/02/26 PHP
用js模拟JQuery的show与hide动画函数代码
2010/09/20 Javascript
扩展JavaScript功能的正确方法(译文)
2012/04/12 Javascript
jquery对dom的操作常用方法整理
2013/06/25 Javascript
JavaScript设计模式之外观模式介绍
2014/12/28 Javascript
JavaScript setTimeout使用闭包功能实现定时打印数值
2015/12/18 Javascript
基于jQuery实现交互体验社会化分享代码附源码下载
2016/01/04 Javascript
15款最好的Bootstrap在线编辑器
2016/08/03 Javascript
Angular2 (RC4) 路由与导航详解
2016/09/21 Javascript
JS实现点击网页判断是否安装app并打开否则跳转app store
2016/11/18 Javascript
基于Vue.js 2.0实现百度搜索框效果
2020/12/28 Javascript
Layui 带多选框表格监听事件以及按钮自动点击写法实例
2019/09/02 Javascript
vue 的 solt 子组件过滤过程解析
2019/09/07 Javascript
webpack3.0升级4.0的方法步骤
2020/04/02 Javascript
js实现拖拽与碰撞检测
2020/09/18 Javascript
pygame学习笔记(4):声音控制
2015/04/15 Python
python把数组中的数字每行打印3个并保存在文档中的方法
2018/07/17 Python
Python线程同步的实现代码
2018/10/03 Python
详解python列表生成式和列表生成式器区别
2019/03/27 Python
对Python中一维向量和一维向量转置相乘的方法详解
2019/08/26 Python
Python SQLAlchemy入门教程(基本用法)
2019/11/11 Python
基于python的docx模块处理word和WPS的docx格式文件方式
2020/02/13 Python
python 使用csv模块读写csv格式文件的示例
2020/12/02 Python
一款纯css3实现的非常实用的鼠标悬停特效演示
2014/11/05 HTML / CSS
html5播放视频且动态截图实现步骤与代码(支持safari其他未测试)
2013/01/06 HTML / CSS
澳大利亚购买太阳镜和眼镜网站:Glamoureyes
2020/09/22 全球购物
结婚邀请函范文
2014/01/14 职场文书
宾馆仓管员岗位职责
2014/07/27 职场文书
张家口市高新区党工委群众路线教育实践活动整改方案
2014/10/25 职场文书
三峡导游词
2015/01/31 职场文书
Python时间操作之pytz模块使用详解
2022/06/14 Python