Python装饰器decorator用法实例


Posted in Python onNovember 10, 2014

本文实例讲述了Python装饰器decorator用法。分享给大家供大家参考。具体分析如下:

1. 闭包(closure)

闭包是Python所支持的一种特性,它让在非global scope定义的函数可以引用其外围空间中的变量,这些外围空间中被引用的变量叫做这个函数的环境变量。环境变量和这个非全局函数一起构成了闭包。

def outer(x):

    y = [1,2,3]

    def inner():

        print x

        print y

    return inner

x = 5    #这个x没有被引用

f = outer(2)

f()

print f.__closure__   #函数属性__closure__存储了函数的环境变量 def entrance(func):
 = 5    #这个x没有被引用f = outer(2)f()print f.__closure__   #函数属性__closure__存储了函数的环境变量 def entrance(func):
x和y都是属于函数outer命名空间的,在inner中被引用,当outer函数退出后,outer的命名空间不存在了,但是inner依然维护了其定义时候对其外部变量x,y的连接。
程序输出:

2

[1, 2, 3]

(, )

装饰器是一个可调用对象(a callable),在Python中,函数是对象,当然也是可调用的,所以装饰器可以是一个函数,我们称其为函数装饰器。
这个可调用对象以一个函数作为参数,闭且返回另一个函数(来替换参数那个函数)。
比如:

def entrance(func):

     def inner():

         print "inside function :", func.__name__

         func()

     return inner

 
entrance是一个装饰器,它是一个函数,它可以接收一个函数func作为参数,返回了另一个函数inner。
那为什么叫装饰器了,在返回函数inner()的内部,调用了func(),而且还作了额外的操作,相当于“装饰”了函数func。
那如何使用装饰器?
def fun1():

    pass

fun1 = entrance(fun1)

def fun2():

    pass

fun2 = entrance(fun2)

 
fun1,fun2的名字都没有变,但是通过调用函数装饰器entrance(),它们已经指向了另一个函数inner(),“装饰了”自己。

@操作符

Python提供的@符号,实质上就是上面做的,对一个函数名进行从新赋值,是语法上的技巧。所以上面的代码等价于

@entrance

def fun1():

    pass

@entrance

def fun2():

    pass

 
2. 装饰器的用途

从这个刻意构造的很简单的例子,可以看出装饰器的意义,如果一个函数需要一个功能,如果这个功能可以被使用在很多函数上,或是函数并不是自己实现,那可以写个装饰器来实现这些功能。
上面的装饰器entrance,装饰一个函数后,函数被调用时会打印出这个函数的名字。
但是有一个问题,这个装饰器从功能上看,是要应该可以用来装饰任何函数,但是如果我们用它来装饰了一个带参数的函数

@entrance

 def fun3(x):

     pass

只要不调用fun3,这三行代码是不会让Python解释器报错的,因为我们已经知道,它等价于:
def fun3(x):

    pass

fun3 = entrance(fun3)

 
我们定义了一个带参的函数fun3,然后把fun3指向了另一个函数inner(),当然不会有什么错。
 
但是,当我们使用fun3时,我们肯定会按照它定义时的样子去使用它,给它传入一个参数。
>>>fun3(1)
这里就会出错了,看看解释器怎么报错的

Traceback (most recent call last):
File “decorator.py”, line 23, in 3water.com <module>
fun3(1)
TypeError: inner() takes no arguments (1 given)

当然我们已经很容易知到为什么会这样报错了,fun3已经不是指向它定义时那个函数了,它现在指向了”inner()”,而inner是没有参数的,当然会出错。
那怎么解决呢?
修改一下inner()的定义,让它可以就收任意个参数就可以了。

def entrance(func):

     def inner(*args, **kvargs):

         print "inside function : ", func.__name__

         func(*args, **kvargs)

     return inner

现在,给inner传任意个参数都不会出错了,也就是entrance可以被用来装饰任何一个函数了。

3. 写个装饰器logger

一个函数被调用时,在日志里记录其名称和被调用的实际参数

def logger(func):

    def inner(*args, **kvargs):

        print  func.__name__, 'called, arguments: ', args, kvargs

        func(*args, **kvargs)

    return inner

希望本文所述对大家的Python程序设计有所帮助。

Python 相关文章推荐
Python 解析XML文件
Apr 15 Python
使用PYTHON接收多播数据的代码
Mar 01 Python
python每次处理固定个数的字符的方法总结
Jan 29 Python
python登录pop3邮件服务器接收邮件的方法
Apr 30 Python
快速解决pandas.read_csv()乱码的问题
Jun 15 Python
python画图的函数用法以及技巧
Jun 28 Python
python程序运行进程、使用时间、剩余时间显示功能的实现代码
Jul 11 Python
对django的User模型和四种扩展/重写方法小结
Aug 17 Python
用Pelican搭建一个极简静态博客系统过程解析
Aug 22 Python
pycharm解决关闭flask后依旧可以访问服务的问题
Apr 03 Python
python tqdm库的使用
Nov 30 Python
Python 带星号(* 或 **)的函数参数详解
Feb 23 Python
python中list循环语句用法实例
Nov 10 #Python
python中MySQLdb模块用法实例
Nov 10 #Python
Python实现子类调用父类的方法
Nov 10 #Python
Python模仿POST提交HTTP数据及使用Cookie值的方法
Nov 10 #Python
Python类的多重继承问题深入分析
Nov 09 #Python
python查询mysql中文乱码问题
Nov 09 #Python
python刷投票的脚本实现代码
Nov 08 #Python
You might like
php实现水仙花数的4个示例分享
2014/04/08 PHP
PHP编程中尝试程序并发的几种方式总结
2016/03/21 PHP
php常用日期时间函数实例小结
2019/07/04 PHP
TFDN图片播放器 不错自动播放
2006/10/03 Javascript
JavaScript之编码规范 推荐
2012/05/23 Javascript
异步动态加载JS并运行(示例代码)
2013/12/13 Javascript
标题过长使用javascript按字节截取字符串
2014/04/24 Javascript
Backbone.js的Hello World程序实例
2015/06/19 Javascript
JavaScript实现刷新不重记的倒计时
2016/08/10 Javascript
JS使用面向对象技术实现的tab选项卡效果示例
2017/02/28 Javascript
微信小程序页面开发注意事项整理
2017/05/18 Javascript
seajs中模块依赖的加载处理实例分析
2017/10/10 Javascript
Vue实现兄弟组件间的联动效果
2020/01/21 Javascript
详解Node.js使用token进行认证的简单示例
2020/05/25 Javascript
Vue+Bootstrap收藏(点赞)功能逻辑与具体实现
2020/10/22 Javascript
Vue使用路由钩子拦截器beforeEach和afterEach监听路由
2020/11/16 Javascript
[08:53]DOTA2每周TOP10 精彩击杀集锦vol.9
2014/06/26 DOTA
[01:07:46]完美世界DOTA2联赛循环赛 Magma vs IO BO2第二场 11.01
2020/11/02 DOTA
Python输出PowerPoint(ppt)文件中全部文字信息的方法
2015/04/28 Python
韩国三大免税店之一:THE GRAND 中文免税店
2016/07/21 全球购物
Free People中国官网:波西米亚风格女装服饰
2016/08/30 全球购物
世界第一冲浪品牌:O’Neill
2016/08/30 全球购物
Woolworth官网:澳洲第一大超市
2017/06/25 全球购物
Uber Eats台湾:寻找附近提供送餐服务的餐厅
2018/05/07 全球购物
日本乐天官方海外转运服务:Rakuten Global Express
2018/11/30 全球购物
Vision Direct比利时:在线订购隐形眼镜
2019/08/27 全球购物
请编写一个 C 函数,该函数在给定的内存区域搜索给定的字符,并返回该字符所在位置索引值
2014/09/15 面试题
简单说下OSPF的操作过程
2014/08/13 面试题
教育课题研究自我鉴定范文
2013/12/28 职场文书
化工专业大学生职业生涯规划书
2014/01/14 职场文书
读书小明星事迹材料
2014/05/03 职场文书
2014年人事科工作总结
2014/11/19 职场文书
2016年中学法制宣传日活动总结
2016/04/01 职场文书
初中运动会闭幕词范本3篇
2019/12/09 职场文书
Arthas排查Kubernetes中应用频繁挂掉重启异常
2022/02/28 MySQL
一文搞懂Java中的注解和反射
2022/06/21 Java/Android