设为首页 收藏本站
查看: 1983|回复: 0

[经验分享] Python装饰器(decorator)

[复制链接]

尚未签到

发表于 2015-4-22 11:51:18 | 显示全部楼层 |阅读模式
  了解装饰器,要先了解闭包。
  
  1,闭包(closure)
  闭包是Python所支持的一种特性,它让在非global scope定义的函数可以引用其外围空间中的变量,这些外围空间中被引用的变量叫做这个函数的环境变量。环境变量和这个非全局函数一起构成了闭包。



1 def outer(x):
2     y = [1,2,3]
3     def inner():
4         print x
5         print y
6     return inner
7
8 x = 5    #这个x没有被引用
9 f = outer(2)
10 f()
11 print f.__closure__   #函数属性__closure__存储了函数的环境变量
  x和y都是属于函数outer命名空间的,在inner中被引用,当outer函数退出后,outer的命名空间不存在了,但是inner依然维护了其定义时候对其外部变量x,y的连接。
  程序输出:
  2
  [1, 2, 3]
  (, )
  
  
  2,装饰器(Decorator)
  装饰器是一个可调用对象(a callable),在Python中,函数是对象,当然也是可调用的,所以装饰器可以是一个函数,我们称其为函数装饰器。
  这个可调用对象以一个函数作为参数,闭且返回另一个函数(来替换参数那个函数)。
  比如:



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



1 def fun1():
2     pass
3 fun1 = entrance(fun1)
4
5 def fun2():
6     pass
7 fun2 = entrance(fun2)
  fun1,fun2的名字都没有变,但是通过调用函数装饰器entrance(),它们已经指向了另一个函数inner(),“装饰了”自己。
  
  @操作符
  Python提供的@符号,实质上就是上面做的,对一个函数名进行从新赋值,是语法上的技巧。所以上面的代码等价于



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



1 @entrance
2 def fun3(x):
3     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
    fun3(1)
TypeError: inner() takes no arguments (1 given)
  当然我们已经很容易知到为什么会这样报错了,fun3已经不是指向它定义时那个函数了,它现在指向了"inner()",而inner是没有参数的,当然会出错。
  
  那怎么解决呢?
  
  修改一下inner()的定义,让它可以就收任意个参数就可以了   【注:参见Python函数一文】



1 def entrance(func):
2     def inner(*args, **kvargs):
3         print "inside function : ", func.__name__
4         func(*args, **kvargs)
5     return inner
  现在,给inner传任意个参数都不会出错了,也就是entrance可以被用来装饰任何一个函数了。
  
  
  3,写个装饰器logger
  一个函数被调用时,在日志里记录其名称和被调用的实际参数



1 def logger(func):
2     def inner(*args, **kvargs):
3         print  func.__name__, 'called, arguments: ', args, kvargs
4         func(*args, **kvargs)
5     return inner
6         
  
  
  
  参考:
  1,http://www.iyunv.com/vamei/archive/2013/02/16/2820212.html   Vamei博客
  2,http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/   12步学习Python decorator

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-59598-1-1.html 上篇帖子: 喝着啤酒学Python(1):搭建环境 下篇帖子: Python图像处理库:Pillow 初级教程
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表