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奇偶行分开存储实现代码
Mar 19 Python
Python针对给定列表中元素进行翻转操作的方法分析
Apr 27 Python
Python基于分析Ajax请求实现抓取今日头条街拍图集功能示例
Jul 19 Python
Python实战之制作天气查询软件
May 14 Python
python爬虫 urllib模块反爬虫机制UA详解
Aug 20 Python
python 监测内存和cpu的使用率实例
Nov 28 Python
pytorch dataloader 取batch_size时候出现bug的解决方式
Feb 20 Python
python 在sql语句中使用%s,%d,%f说明
Jun 06 Python
Django QuerySet查询集原理及代码实例
Jun 13 Python
Python限制内存和CPU使用量的方法(Unix系统适用)
Aug 04 Python
10个示例带你掌握python中的元组
Nov 23 Python
pycharm Tab键设置成4个空格的操作
Feb 26 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数据采集的详解
2013/06/02 PHP
php中的单引号、双引号和转义字符详解
2017/02/16 PHP
PHP实现的Redis多库选择功能单例类
2017/07/27 PHP
Javascript 判断函数类型完美解决方案
2009/09/02 Javascript
屏蔽网页右键复制和ctrl+c复制的js代码
2013/01/04 Javascript
使用JSLint提高JS代码质量方法分享
2013/12/16 Javascript
jQuery响应鼠标事件并隐藏与显示input默认值
2014/08/24 Javascript
jQuery实现hover合成事件的方法
2015/08/06 Javascript
js实现颜色阶梯渐变效果(Gradient算法)
2017/03/21 Javascript
使用jQuery卸载全部事件的思路详解
2017/04/03 jQuery
jackson解析json字符串,首字母大写会自动转为小写的方法
2017/12/22 Javascript
你应该了解的JavaScript Array.map()五种用途小结
2018/11/14 Javascript
vue自定义指令的创建和使用方法实例分析
2018/12/04 Javascript
如何制作一个Node命令行图像识别工具
2018/12/12 Javascript
微信小程序常见页面跳转操作简单示例
2019/05/01 Javascript
layui点击左侧导航栏,实现不刷新整个页面,只刷新局部的方法
2019/09/25 Javascript
nodeJs的安装与npm全局环境变量的配置详解
2020/01/06 NodeJs
javascript 内存模型实例详解
2020/04/18 Javascript
es6函数之箭头函数用法实例详解
2020/04/25 Javascript
解决Vue-cli3没有vue.config.js文件夹及配置vue项目域名的问题
2020/12/04 Vue.js
wxPython窗口中文乱码解决方法
2014/10/11 Python
python中list循环语句用法实例
2014/11/10 Python
python获取文件后缀名及批量更新目录下文件后缀名的方法
2014/11/11 Python
Python 查看文件的读写权限方法
2018/01/23 Python
python 用lambda函数替换for循环的方法
2018/06/09 Python
基于Python-Pycharm实现的猴子摘桃小游戏(源代码)
2021/02/20 Python
为奢侈时尚带来了慈善元素:Olivela
2018/09/29 全球购物
俄罗斯金苹果网上化妆品和香水商店:Goldapple
2019/12/01 全球购物
EJB的几种类型
2012/08/15 面试题
护理专科毕业推荐信
2013/11/10 职场文书
《跨越海峡的生命桥》教学反思
2014/02/24 职场文书
晚会开幕词
2015/01/28 职场文书
护士岗位竞聘书
2015/09/15 职场文书
聘任书范文大全
2015/09/21 职场文书
详细分析PHP7与PHP5区别
2021/06/26 PHP
Java基础之详解HashSet的使用方法
2021/06/30 Java/Android