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

[经验分享] Python装饰器(Decorator)简介

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2015-12-3 09:38:04 | 显示全部楼层 |阅读模式
  Python有许多出色的语言特性,装饰器(Decorator)便是其中一朵奇葩。先来看看一段代码:



def deco1(f):
print 'decorate 1'
return f
def deco2(f):
print 'decorate 2'
return f
@deco1
@deco2
def foo():
return 'hello'
  保存并执行上面的代码,你会看到如下输出:



decorate 2
decorate 1
  函数foo没有被调用,但是deco1,deco2被按照一个顺序被调用了。deco1和deco2就是装饰器。从上面的输出可以看出两点:
  1 装饰器是在代码装载时被调用的
  2 调用的顺是从下到上
  现在来说说装配器到底做了什么。看代码:



def deco1(f):
print 'decorate 1',f
return f
def deco2(f):
print 'decorate 2',f
return f
@deco1
@deco2
def foo():
return 'hello'
  这段代码的执行结果为:



decorate 2 <function foo at 0x00000000021F79E8>
decorate 1 <function foo at 0x00000000021F79E8>
  装饰器函数的参数‘f’被打印出来,而且就是我们的函数‘foo’,可见装饰器的参数就是被装饰的函数。真的是这样吗?再来看代码:



def wraper(n,f):
def foo1():
return '%s(%s)'%(n,f())return foo1

def deco1(f):
print 'decorate 1',f
return wraper('decorate 1',f)
def deco2(f):
print 'decorate 2',f
return wraper('decorate 2',f)
@deco1
@deco2
def foo():
return 'hello'
  这段代码的执行结果为:



decorate 2 <function foo at 0x0000000002147A58>
decorate 1 <function foo1 at 0x0000000002147AC8>
  我觉得我现在可以总结一下了:
  1 装饰器在代码装载时被调用;
  2 调用顺序是从下到上的;
  3 被装饰函数‘foo’作为参数传递给第一个装饰器‘deco2’,返回值将作为参数传递给第二个装饰器‘deco1’,然后依次向上直到最顶端的装饰器;
  4 最顶端的装饰器的返回值就是被装饰以后的函数,我们暂时称之为,也就是我们将来要执行的那个‘foo’。
  下面,来我们说说装饰后的函数,被调用会有什么结果,看代码:
  



def wraper(n,f):
def foo1():
return '%s(%s)'%(n,f())
return foo1
def deco1(f):
print 'decorate 1',f
return wraper('decorate 1',f)
def deco2(f):
print 'decorate 2',f
return wraper('decorate 2',f)
@deco1
@deco2
def foo():
return 'hello'

print foo()
  这段代码的执行结果为:



decorate 2 <function foo at 0x0000000002127A58>
decorate 1 <function foo1 at 0x0000000002127AC8>
decorate 1(decorate 2(hello))
  不难看出,调用顺序与装饰顺序刚好相反,最终函数也就是最顶端的装饰器返回的函数最先被调用,然后依次调用到最初那个函数‘foo’。我在这里故意规避了一个基本的事实,就是:其实最后被调用的就是顶端装饰返回的那个函数,你必须手动在这个函数中调用前面的函数,见这里:



return '%s(%s)'%(n,f())
  ,才会产生调用连的效果。所以装饰器并不会帮你完成所有的事情,他给了你充分的自由。说的这里,你们要问了(如果你有足够的好奇心):‘装饰器能带参数吗’。答案是能,见下面的代码:
  



def wraper(n,f):
def foo1():
return '%s(%s)'%(n,f())
return foo1
def deco(n):
def deco1(f):
print n,f
return wraper(n,f)
return deco1
@deco('decorate 1')
@deco('decorate 2')
def foo():
return 'hello'

print foo()
  这段代码的执行结果为:



decorate 2 <function foo at 0x0000000002117AC8>
decorate 1 <function foo1 at 0x0000000002117B38>
decorate 1(decorate 2(hello))
  哇,和之前的结果一模一样,代码还被简化了不少。这是怎么回事呢,我来简单解释下,函数‘deco’不是装饰器,他只是一个返回装饰器的函数,当你把它放到装饰符号‘@‘后面时,python的语法起了一个美妙的作用,他会先调用这个函数,然后用返回值值作为装饰器。
  大概就是这样啦,语法大师也许会描述的更详细更专业。源码狂人还可能深入到python的C代码里寻找成因。不过,作为一个有理智的好青年我们就点到为止吧。
  下次,我们再来掰扯一下,装饰器都可以变出哪些戏法吧。洗洗睡了。
  

运维网声明 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-146652-1-1.html 上篇帖子: [Leetcode] Add Two Numbers @Python 下篇帖子: ubuntu eclipse 中安装 python + PyDev
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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