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

[经验分享] python之理解“@”(装饰器/decorators)

[复制链接]

尚未签到

发表于 2017-5-1 12:01:40 | 显示全部楼层 |阅读模式
前言

 
初学python时,第一次见到“@”符号,感觉很眼熟,如果是学习过java或者接触过AOP(面向切面编程),对于这个符号应该是比较熟悉的。实际上,python中的@也是AOP思想的一种实现。
 
python的@,官方语言叫做“decorators”,即装饰器。这是python的一大特性,对于初学者来说,很难透彻的理解decorators。本文以多个python例子为引,层层深入,帮助读者来透彻的理解decorators。
 

从函数开始

 
decorators和函数是密不可分的,因此必须对python的函数有所了解,之前我写过一篇函数基础的博客,链接如下:http://yunjianfei.iteye.com/blog/2186064
 
通过该博客,主要要了解的是:
1. 函数的基本概念:函数名、实参、形参、函数体、函数返回值
2. 作用域、生存周期的概念
 

嵌套函数与闭包

 
要理解decorator,嵌套函数与闭包也是需要了解的知识,这里我单独写了一个博客,链接如下:

http://yunjianfei.iteye.com/blog/2186092

通过该博客,主要要了解的是:
1. 函数是对象,所以函数可以在另一个函数中定义(嵌套函数)
2. 函数也可以赋给另一个变量 (类似C语言的函数指针)
3. 函数可以作为参数,也可以作为返回值(不执行该函数,只是返回)
4. 闭包是内部函数可以使用外部函数变量的机制
 
 

装饰器(Decorators)

 
装饰器其实就是调用时,把一个函数作为参数,把此函数封装后,返回一个替代函数。
读起来有点抽象,换句话说:装饰器其实就是在不修改原函数的基础上,在执行原函数的前后执行别的代码
 
我们看一个简单的例子,下面是手动实现的一个装饰器。
 

#!/usr/bin/env python
def outer(some_func):
def inner():
print "before some_func"
ret = some_func() # 1
return ret + 1
return inner
def foo():
return 1
decorated = outer(foo) # 2
print decorated()
print "decorated 's __name__ : " + decorated.__name__      
 输出结果:

before some_func
2
decorated 's __name__ : inner

 
这个例子有以下要点:
1. outer函数有一个名为some_func的参数,在outer函数里定义了一个嵌套函数inner,outer将inner函数作为       返回值返回(注意:并没有去调用inner,只是将inner作为变量返回
2. inner函数打印了一行字符串,然后调用了some_func,并且在#1处获取了some_func的返回值
3. outer每次调用时,参数some_func的值可能会不同,但是我们都会在inner中去调用这个函数。
4. inner在结束时,其返回值是some_func()+1
5. 在#2处,调用了outer函数(foo函数作为参数),并将返回的inner函数作为赋值给decorated 
6.最后调用decorated()函数,执行inner,打印一行,并在inner中调用foo函数,最后返回2
 
上面这个例子可以用一句话概括:变量decorated是将foo函数装饰后(封装后)的版本,或者说,foo函数前后附加其他的一些代码。
 

decorated = outer(foo)
上面的这一行代码其实就是装饰器的本质。下面的例子用我们一般见到的“@”,也就是装饰器的一般用法来写,如下:

#!/usr/bin/env python
def outer(some_func):
def inner():
print "before some_func"
ret = some_func() # 1
return ret + 1
return inner
@outer
def foo():
return 1
print foo()
print "foo's __name__ : " + foo.__name__  #2
执行结果为:

before some_func
2
foo's __name__ : inner

 
上面的两套代码是等价的。
 
@outer这一行,实际上执行的就是

foo = outer(foo)
 
注意:#2处打印了foo的__name__,打印结果为:inner。这再次印证了我们开头处的一句话:
函数装饰器就是把一个函数作为参数,把此函数封装后,返回一个替代函数。
对应上面的代码,就是:
outer装饰器,把foo函数作为参数,把foo封装成inner后,返回inner。
 
 

一定要用嵌套函数吗

 
第一次看到装饰器的时候,估计有很多人都疑惑过,为啥就是嵌套函数呢?好吧,其实也可以不用嵌套函数的,看下面的例子:

#!/usr/bin/env python
some_func = None #1
def outer(func):
global some_func
some_func = func #2
return inner
def inner():
print "before some_func"
ret = some_func() # 3
return ret + 1
@outer
def foo():
return 1
print foo()
print "foo's __name__ : " + foo.__name__
 
这个例子比上面嵌套函数的装饰器版本复杂了不少,但是效果是等同的。这样一比较,从各个角度来看,嵌套函数的写法显然要简洁很多。
 

收尾

 
 上面介绍装饰器的时候,其实只是介绍了装饰器里最基本的部分,函数装饰器相关,鉴于篇幅,暂时先不在这里写了。
 
 
 
 
 
 
 

 

 
 

运维网声明 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-371598-1-1.html 上篇帖子: Python 学习入门(33)—— 内置函数 下篇帖子: 第一次用python写爬虫
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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