zoukankan      html  css  js  c++  java
  • 装饰器

    今天呢。我们聊一下装饰器。

    什么是装饰器呢?肯定是能给其他东西装饰一些东西。

    其实。装饰器的本质就是一个闭包。

    装饰器的原则:开放封闭原则,说的简单点就是在不改变原函数的调用方式。给当前函数增加一些功能

    先来看一下。装饰器长什么样。

    def wapper(func):
        def inner(*args, **kwargs):
            print('start')
            func()
            print('end')
        return inner
    @wapper
    def index():
        print('this is index')
    index()
    
    ------------------------------
    结果
    start
    this is index
    end

    在上面代码中,函数wapper就是一个装饰器

    现在。让我们看一下这是什么原理

    其实比较关键的一句是 @wapper ,@wapper 是一个语法糖,他原本的样子是 index = wapper(index) ,wapper 括号内的参数是要被装饰的函数

    1,在代码从上下行运行时,遇到wapper 定义wapper函数

    2,在遇到index,定义index函数

    3,遇到@wapper 会先执行@wapper 并把要装饰的函数传入wapper函数中,返回值是inner函数  ,这个时候,index = Inner

    4,在遇到index()时。执行的不是index函数。而是上面的index = inner,也就是执行inner函数

    5,在执行innner函数时。打印了 start

    6,inner函数的func() 执行的是index函数。在执行wapper时。index函数已经被传入,只是在wapper中没有调用,在inner调用了而已,这也是闭包的体现

    7,执行index函数。打印this is index ,函数特性:哪里调用回到哪里,执行完毕后回到inner函数

    8,打印 end ,整体执行完毕

    上面就是一个简单的装饰器执行过程。我们可以在某个函数执行之前或者之后给他加一下额外的功能了。

    既然说到这里。那就在聊一下带参数的装饰器,

    先看一下下面这段代码

     1 def Before(request):
     2     print 'before'
     3 
     4 def After(request):
     5     print 'after'
     6 
     7 def Filter(before_func,after_func):
     8     def outer(main_func):
     9         def wrapper(request):
    10             before_result = before_func(request)
    11             if(before_result != None):
    12                 return before_result;
    13             main_result = main_func(request)
    14             if(main_result != None):
    15                 return main_result;
    16             after_result = after_func(request)
    17             if(after_result != None):
    18                 return after_result;
    19         return wrapper
    20     return outer
    21 
    22 @Filter(Before, After)
    23 def Index(request):
    24     print 'index'
    25 
    26 Index('example')
    
    先上结果:
    before
    index
    after
    View Code

    这段代码看起来就很高大上了。看起来有点懵。不要慌。在看下下面这张执行顺序图

    看上面这张图,先来统一解释一下,代码前面的数字是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,这其实就是装饰器参数祖坟里的秘密了。不要问我172125步后面为什么没有执行,因为我们的函数都没有返回值呀!

    快去给你代码加一个装饰器吧~~

  • 相关阅读:
    C# 调用cmd执行指令
    如何发布 silverlight wcf 简单易学
    C#读取特定目录下的所有文件
    用批处理bat一次安装所有的系统更新补丁
    动态创建datagrid序号
    学习DIV+CSS一个最简单的布局一行三列DIV代码!
    highslide图片查看特效
    相册程序mageVue
    让Apache支持ASP.NET
    ASP.NET四种页面导航方式之比较与选择
  • 原文地址:https://www.cnblogs.com/Rxtong/p/11065370.html
Copyright © 2011-2022 走看看