zoukankan      html  css  js  c++  java
  • 转-简单了解Python装饰器实现原理

    转载文章链接:https://blog.csdn.net/MonaLisaTearr/article/details/80661937

    有过开发经验得朋友队装饰模式这个词应该不陌生,装饰装饰,顾名思义就是指对我们原来有得东西进行装饰,比如我们买了新房,那么我们对毛坯房的装修,就是对我们房子进行拓展,让它更加完善!同样得对于代码也是如此,我们就是对我们原有的功能进行功能的拓展!

    一、假设我们有下面的一个场景

    1、假设你现在是某个公司的工程师,你当前负责得事情就是公司某个项目整个系统架构基本功能得开发,后续会有很多同事会直接调用你写得功能函数。于是你就风风火火得一顿狂撸,终于有了下面代码:
    def test1():
    print("====给员工加薪了!====")

    def test2():
        print("====出新版本,杀一个程序员祭天!====")
    很好,同事们调得很舒服,系统跑得很好,老板赚钱。。。


    2、某一天,老板突然来找你,说有个员工莫名奇妙被加薪了,并不是老板自己加的,老板说,加薪这里要验证下,只有我才有权限给员工加薪。又说最近程序员急剧减少,被杀得太多了,也要加权限,只有老板才能杀!

    3、作为一个出色得程序员,这点要求当然没问题,于是你又一顿加班加点狂改,把老板的需求都是实现了,于是又有了下面的代码:
    def test1():
        if ROLE == "boss":
    print("====给员工加薪了!====")
        else:
    print("====不好意思,您不是老板====")

    def test2():
        if ROLE == "boss":
            print("====出新版本,杀一个程序员祭天!====")
        else:
    print("====不好意思,您不是老板====")
    4、这一切看起来很正常,但是我们不妨假设下,如果有10000个类似得功能函数需要添加类似得验证、又或者添加其它的功能呢?我们姑且假设你单身多年得手速非常快,但是这样搞法也是很浪费时间的吧?更何况贸然得去改动原来得代码,风险也是不小的,所以我们换下面这种方式看看!

    二、闭包得引入
    1、之前我已经分享过闭包的学习笔记了,不了解的可以去看下,闭包得几个条件如下:一个函数内定义了内函数,并且内涵是使用了外函数的局部变量,最后外函数返回了内涵的引用。满足了这三个条件我们就可以称之为闭包。

    2、那么我们到底引入闭包做什么呢?闭包又是如何解决我们上面的问题得呢?我们先看下下面这段代码:

    def iwapper(fun):
        inner():
            if ROLE == "boss":
        print("====身法验证通过====")
        fun()
    else:
        print("====不好意思,您不是老板====")
        return inner

    def test1():
    print("====给员工加薪了!====")

    def test2():
        print("====出新版本,杀一个程序员祭天!====")


    #调用iwapper,并传入test1函数的引用,给员工加薪
    addMoney = iwapper(test1)
    addMoney ()

    #调用iwapper,并传入test2函数的引用,杀程序员
    killDev = iwapper(test2)
    killDev()
    打印下结果:

     

    此时,我们产生了两个新函数,一个是addMoney(),另一个是killDev(),调用这两个即实现了添加验证得功能,保持了原来功能函数不用修改,并且大大减少了代码得冗余,但是另一个问题又来了,代码得调用方式变了,我们需要告知其他所有人,修改他们得代码!很显然这是一个更糟糕得做法!

    3、路总是一步步走出来得,经历了那么多波折,真相也越来越接近了,聪明得你很快又拿出了下面得方案:

    def iwapper(fun):
        inner():
            if ROLE == "boss":
        print("====身法验证通过====")
        fun()
    else:
        print("====不好意思,您不是老板====")
        return inner

    def test1():
    print("====给员工加薪了!====")

    def test2():
        print("====出新版本,杀一个程序员祭天!====")

    #调用iwapper,并传如test1函数的引用,给员工加薪
    test1 = iwapper(test1)
    test ()

    #调用iwapper,并传如test2函数的引用,杀程序员
    test2 = iwapper(test2)
    test2()
    打印下结果:

     


            这里我们可以看到我们并没有对原有功能函数进行修改,并且提供给外部调用得方式依然是test1()、test2(),已经满足了我们得条件了,那么我们一步步的分析下:
    1>首先定义了一个test1()函数的时候,就相当于再内存中创建了一块内存区域,我们姑且叫它A。同样得我们在定义iwapper(fun)的时候,在其内部定义了inner()函数,我们姑且把它所指向的内存区域命名为B。
    2>紧接着,当我们调用iwapper(test1)的时候,我们把test1()的引用传了进去,所以fun此时指向了test1()的引用,也就是指向了A
    3>接下来我们使用test1接收了iwapper(fun)得返回值,而iwapper(fun)返回得是inner()的引用,所以此时test1指向了B
    4>所以最后我们调用test1()函数得时候其实是调用了inner(),而inner()函数除了进行校验功能之外还调用了fun()函数,从第二点我们可以知道,fun指向了A也就是最开始定义得test1(),这样我们即进行了验证功能,又对原来功能进行调用!
    三、装饰器
    1、说了那么多,我们来看看如果遇到上面的需求,如果使用Python装饰器来实现的话会怎么样?看下面代码:

    def iwapper(fun):
        inner():
            if ROLE == "boss":
        print("====身法验证通过====")
        fun()
    else:
        print("====不好意思,您不是老板====")
        return inner

    @iwapper
    def test1():
    print("====给员工加薪了!====")

    @iwapper
    def test2():
        print("====出新版本,杀一个程序员祭天!====")
    那么看下效果:

     

    很明显,效果实现了,这时候也许就又朋友要说道说道了,nmmp,Python解析器那么简单,你前面说那么多废话干嘛,直接一开始就来这段不就行了?朋友莫激动,先把刀放下,其实如果我们单看最后面的代码,我们仅仅知道@iwapper是python装饰器的实现方式而已,但是我们并不知道这句代码到底干了什么事,而我们前面说的就是python解析器的实现原理了!其中得思想获取会对我们有所帮助也不一定呢!


    总结:这里仅仅是对Python中装饰器得最简单使用方式进行学习,更重要得是学习Python决绝类似问题的思想!其更多用法大家可以查阅相关得资料,比如说带参数的装饰器,多个装饰器一起使用等等!
    ————————————————
    版权声明:本文为CSDN博主「变异的小江江」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/MonaLisaTearr/article/details/80661937

  • 相关阅读:
    Java 中无参带返回值方法的使用
    Java 中无参无返回值方法的使用
    如何定义 Java 中的方法
    Java 中的二维数组
    使用 foreach 操作数组
    使用 Arrays 类操作 Java 中的数组
    如何使用 Java 中的数组
    Java 循环语句之多重循环
    UML常用图的几种关系的总结
    JAVA 对象引用,以及对象赋值
  • 原文地址:https://www.cnblogs.com/24Key/p/11923473.html
Copyright © 2011-2022 走看看