python 找到装饰器_python装饰器

装饰器是什么呢?

我们先来打一个比方,我写了一个python的插件,提供给用户使用,但是在使用的过程中我添加了一些功能,可是又不希望用户改变调用的方式,那么该怎么办呢?

这个时候就用到了装饰器。装饰器的原理是什么?我们接下来就一步一步看过来!

假如我们有一个home函数如下:

defhome():

print 'this is the home page!'

而我们希望用户在访问home函数之前先验证一下权限,那么在不改变用户调用方法的情况下,就需要在home中调用一个login函数,就像这样:

48304ba5e6f9fe08f3fa1abda7d326ab.png

deflogin(usr):

if usr == 'xs':

returnTrue

defhome():

result =login()

ifresult:

print 'this is the home page!'

48304ba5e6f9fe08f3fa1abda7d326ab.png

这样可以实现我们的需求,但是我们看到home的代码发生了很大的变化,所有的代码都要被包裹在一个if语句中,并且要进行缩进,这往往不是我们希望看到的。那么我们还可以怎么做呢? 首先我们看一个小例子:

defhome():

print 'this is the home page!'

printhome

输出:

我们定义了一个home函数,但是并不使用home()调用它,而是让程序打印出home方法的地址。

那么我们再看这段代码:

48304ba5e6f9fe08f3fa1abda7d326ab.png

deflogin(usr):

if usr == 'xs':

returnTrue

defwrapper(funcname):

if login('xs'):

returnfuncname

defhome():

print 'this is the home page!'home =wrapper(home)

home()

输出的结果:this is the home page!

48304ba5e6f9fe08f3fa1abda7d326ab.png

我们可以看到这段代码的点睛之笔就在这句:“home = wrapper(home)”,我们将home函数的地址当做参数传给了wrapper方法,在wrapper方法中进行验证,验证通过之后再将home方法的地址返回,这个之后再调用home,我们就在没有修改home方法的情况下,调用了home,是不是方便了很多?这就是装饰器的概念! 但是很快我们发现这种方法还是不好,因为用户必须加上那句点睛之笔的代码再执行原本想执行的home方法,于是在python中就规定装饰器可以这样使用:

48304ba5e6f9fe08f3fa1abda7d326ab.png

deflogin(usr):

if usr == 'xs':

returnTrue

defwrapper(funcname):

if login('aaa'):

returnfuncname

@wrapper

defhome():

print 'this is the home page!'

13 home()

48304ba5e6f9fe08f3fa1abda7d326ab.png

看到了吧,我们只需要在home方法上加上一个“@wrapper”,就可以省去原本在home()方法前写的那句话了,这样就方便了很多,而且也没有改变用户的调用方式。 然而,你有没有想过,怎么使用装饰器传递参数?

defhome(usr):

print 'this is the home page!'

我们来看看下面的实现方法:

48304ba5e6f9fe08f3fa1abda7d326ab.png

defwrapper1(funcname):

print 'funcname:',funcname

defwrapper2(argv):

iflogin(argv):

print 'funcname:',funcname

returnfuncname(argv)

else:

returnerror

returnwrapper2

defhome(usr):

print 'this is the home page!'

print 'hello ,',usr

home =wrapper1(home)

home('xs')

输出的结果:

funcname: funcname: this isthe home page!

hello , xs

48304ba5e6f9fe08f3fa1abda7d326ab.png

解决啦,我们实现了装饰器的传参,那么如果我想传多个参数,不确定的参数可不可以呢?当然可以啦,你就用动态传参就好了呀~~~

看到这里基本上普通青年就够用了。但是作为一个文艺小青年,你愿不愿意用一个晚上的时间,来刨一刨装饰器的祖坟?

先来看多个装饰器的应用。

48304ba5e6f9fe08f3fa1abda7d326ab.png

defwrapper1(func):

definner():

print 'w1,before'func()

print 'w1,after'

returninner

defwrapper2(func):

definner():

print 'w2,before'func()

print 'w2,after'

returninner

@wrapper2

@wrapper1

deffoo():

print 'foo'foo()

运行结果:

w2,before

w1,before

foo

w1,after

w2,after

48304ba5e6f9fe08f3fa1abda7d326ab.png

从上面这个例子我们可以看出,装饰器就像是一个俄罗斯套娃,把被装饰的方法当成最小的一个娃娃,封装在最内层,外面一层一层的嵌套装饰器。

接下来再看一个装饰器传递函数参数的例子:

48304ba5e6f9fe08f3fa1abda7d326ab.png

defBefore(request):

print 'before'

defAfter(request):

print 'after'

defFilter(before_func,after_func):

defouter(main_func):

defwrapper(request):

before_result =before_func(request)

if(before_result !=None):

returnbefore_result;

main_result =main_func(request)

if(main_result !=None):

returnmain_result;

after_result =after_func(request)

if(after_result !=None):

returnafter_result;

returnwrapper

returnouter

@Filter(Before, After)

defIndex(request):

print 'index'Index('example')

先上结果:

before

index

after

48304ba5e6f9fe08f3fa1abda7d326ab.png

首先,index里我只是随便传了一个参数,并没有什么实际的意义,不要被迷惑了。接下来看看这段代码的执行过程:

fe3d171804227e376eff5ec079b07e4b.png

看上面这张图,先来统一解释一下,代码前面的数字是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步后面为什么没有执行,因为我们的函数都没有返回值呀!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值