python——挖装饰器祖坟事件
装饰器是什么呢?
我们先来打一个比方,我写了一个python的插件,提供给用户使用,但是在使用的过程中我添加了一些功能,可是又不希望用户改变调用的方式,那么该怎么办呢?
这个时候就用到了装饰器。装饰器的原理是什么?我们接下来就一步一步看过来!
假如我们有一个home函数如下:
def home():
print 'this is the home page!'
而我们希望用户在访问home函数之前先验证一下权限,那么在不改变用户调用方法的情况下,就需要在home中调用一个login函数,就像这样:
def login(usr):
if usr == 'Eva_J':
return True
def home():
result = login()
if result:
print 'this is the home page!'
这样可以实现我们的需求,但是我们看到home的代码发生了很大的变化,所有的代码都要被包裹在一个if语句中,并且要进行缩进,这往往不是我们希望看到的。那么我们还可以怎么做呢?
首先我们看一个小栗子:
def home():
print 'this is the home page!' print home 输出:<function home at 0x000000000219C978>
我们定义了一个home函数,但是并不使用home()调用它,而是让程序打印出home方法的地址。
那么我们再看这段代码:
def login(usr):
if usr == 'Eva_J':
return True
def wrapper(funcname):
if login('Eva_J'):
return funcname
def home():
print 'this is the home page!' home = wrapper(home)
home()
输出的结果:this is the home page!
我们可以看到这段代码的点睛之笔就在这句:“home = wrapper(home)”,我们将home函数的地址当做参数传给了wrapper方法,在wrapper方法中进行验证,验证通过之后再将home方法的地址返回,这个之后再调用home,我们就在没有修改home方法的情况下,调用了home,是不是方便了很多?这就是装饰器的概念!
但是很快我们发现这种方法还是不好,因为用户必须加上那句点睛之笔的代码再执行原本想执行的home方法,于是在python中就规定装饰器可以这样使用:
def login(usr):
if usr == 'Eva_J':
return True def wrapper(funcname):
if login('aaa'):
return funcname @wrapper
def home():
print 'this is the home page!'
12
home()
看到了吧,我们只需要在home方法上加上一个“@wrapper”,就可以省去原本在home()方法前写的那句话了,这样就方便了很多,而且也没有改变用户的调用方式。
然而,你有没有想过,怎么使用装饰器传递参数?
def home(usr):
print 'this is the home page!'
我们来看看下面的实现方法:
def wrapper1(funcname):
print 'funcname:',funcname
def wrapper2(argv):
if login(argv):
print 'funcname:',funcname
return funcname(argv)
else:
return error
return wrapper2 def home(usr):
print 'this is the home page!'
print 'hello ,',usr home = wrapper1(home)
home('Eva_J')
输出的结果:
funcname: <function home at 0x00000000022CFAC8>
funcname: <function home at 0x00000000022CFAC8>
this is the home page!
hello , Eva_J
解决啦,我们实现了装饰器的传参,那么如果我想传多个参数,不确定的参数可不可以呢?当然可以啦,你就用动态传参就好了呀~~~
看到这里基本上普通青年就够用了。但是作为一个文艺小青年,你愿不愿意用一个晚上的时间,来刨一刨装饰器的祖坟?
先来看多个装饰器的应用。
def wrapper1(func):
def inner():
print 'w1,before'
func()
print 'w1,after'
return inner def wrapper2(func):
def inner():
print 'w2,before'
func()
print 'w2,after'
return inner @wrapper2
@wrapper1
def foo():
print 'foo' foo() 运行结果:
w2,before
w1,before
foo
w1,after
w2,after
从上面这个例子我们可以看出,装饰器就像是一个俄罗斯套娃,把被装饰的方法当成最小的一个娃娃,封装在最内层,外面一层一层的嵌套装饰器。
接下来再看一个装饰器传递函数参数的例子:
def Before(request):
print 'before' def After(request):
print 'after' def Filter(before_func,after_func):
def outer(main_func):
def wrapper(request):
before_result = before_func(request)
if(before_result != None):
return before_result;
main_result = main_func(request)
if(main_result != None):
return main_result;
after_result = after_func(request)
if(after_result != None):
return after_result;
return wrapper
return outer @Filter(Before, After)
def Index(request):
print 'index' Index('example') 先上结果:
before
index
after
首先,index里我只是随便传了一个参数,并没有什么实际的意义,不要被迷惑了。接下来看看这段代码的执行过程:
看上面这张图,先来统一解释一下,代码前面的数字是python在执行Index之前做的事情,它将这段代码中函数的地址写入内存,方便之后在调用中可以一下子找到。
在装饰器这里有点绕,来来回回了好几次,我们解释一下从第3步往后的步骤,首先是在第3步这里,解释器发现了这个函数,并把它放进了内存里,然后第4步又读到了一个装饰器,它就从内存里找到装饰器的地址返回到了第5步这个装饰器的位置。继续往下读,第6步它又把发现了一个outer函数,于是欢欢喜喜的把outer函数的地址放进了内存里,然后就停止了,因为它很清楚它不是来执行outer的,所以它调过了这个函数并顺序执行了这个函数外面的第一句话:第7步,return outer。这个时候解释器发现这不就是刚刚记下了地址的那个方法么?它就又回来了之前的地址,找到了outer函数。。。就是这样,直到执行到第10步return wrapper,这里我没有写,其实它也是兴冲冲的回到了家wrapper方法那里的,但是它发现下面已经没有它需要记录地址的函数了。所以它把最后的这个wrapper函数的地址返回给了装饰器,也就是装饰器下面的index方法。
这个时候,好巧不巧的,我们在程序中调用了这个index方法,那么解释器就把我们领到wrapper那里开始执行了,在wrapper里我们可以使用外层函数传过来的方法参数Before和After,这其实就是装饰器参数祖坟里的秘密了。不要问我17\21\25步后面为什么没有执行,因为我们的函数都没有返回值呀!
ok,刨祖坟活动结束,关机,睡觉!
参考文章:
http://www.cnblogs.com/wupeiqi/articles/4980620.html
python——挖装饰器祖坟事件的更多相关文章
- Python各式装饰器
Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...
- Python札记 -- 装饰器补充
本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: #!/usr/bin/env python def deco(func): def ...
- python基础——装饰器
python基础——装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25 ...
- 【转】详解Python的装饰器
原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...
- 两个实用的Python的装饰器
两个实用的Python的装饰器 超时函数 这个函数的作用在于可以给任意可能会hang住的函数添加超时功能,这个功能在编写外部API调用 .网络爬虫.数据库查询的时候特别有用 timeout装饰器的代码 ...
- python 基础——装饰器
python 的装饰器,其实用到了以下几个语言特点: 1. 一切皆对象 2. 函数可以嵌套定义 3. 闭包,可以延长变量作用域 4. *args 和 **kwargs 可变参数 第1点,一切皆对象,包 ...
- 理解Python中的装饰器//这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档
转自:http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html 这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档 ...
- python基础—装饰器
python基础-装饰器 定义:一个函数,可以接受一个函数作为参数,对该函数进行一些包装,不改变函数的本身. def foo(): return 123 a=foo(); b=foo; print(a ...
- 详解Python的装饰器
Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...
随机推荐
- 微信公众平台开发(26) ACCESS TOKEN
本文介绍微信公众平台下Access Token的概念及获取方法. 一.Access Token access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.正常 ...
- SQLServer性能调优3之索引(Index)的维护
前言 前一篇的文章介绍了通过建立索引来提高数据库的查询性能,这其实只是个开始.后续如果缺少适当的维护,你先前建立的索引甚至会成为拖累,成为数据库性能的下降的帮凶. 查找碎片 消除碎片可能是索引维护最常 ...
- [PCL]FPFH描述子
fpfh_est.setSearchSurface(data); 如果没有设置SearchSurface,使用input数据集作为查找的表面 // If no search surface has b ...
- iis 重新注册 .net 方法
dhl:IIS注册ASP.NET 1.1.2.0.4.0_在win7下如果先安装vs2010 后安装iis7的话,必须注册iis才可以用.~~~!!鄙视微软 IIS中ASP.NET的版本号此时可选 ...
- 前向后瞻正则表达式及其JS例子
定义 x(?=y) 匹配'x'仅仅当'x'后面跟着'y'.这种叫做正向肯定查找. 比如,/Jack(?=Sprat)/会匹配到'Jack'仅仅当它后面跟着'Sprat'./Jack(?=Sprat|F ...
- js match() 方法
方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配.
- Java -- 在Eclipse上使用Spring
在.NET上用的VS.NET+Spring.net+Nhibernate,到了Java平台上,自然对应着Eclipse+Spring+Hibernate.上一篇文章介绍了如何在Eclipse上使用Hi ...
- ReferenceEquals和 == 和equals()的比较
对于这几点的区别网上经常有各种答案,而且常常会出现答案之间是互相矛盾的.要嘛就是根本含糊的解释不清楚,只是把测试结果扔上来并没有言简意赅的写出他们之间的比较.难道面试的时候考官问你,你也要在纸上写一大 ...
- mui记录
事件addEventListener()绑定事件的对象方法.addEventListener()含有三个参数,一个是事件名称,另一个是事件执行的函数,最后一个是事件捕获.obj.addEventLis ...
- svn使用方法介绍(1)
TotoiseSVN的基本使用方法 在 项目管理实践教程一.工欲善其事,必先利其器[Basic Tools]中,我已经讲解了怎样安装TortoiseSVN.在上面的讲解中已经讲了怎么使用VisualS ...