zoukankan      html  css  js  c++  java
  • Python函数之装饰器

              装饰器

    一.装饰器的意义

      比如:以下函数是供我们调用的,但是我们需要在每个函数中都添加同一个功能,该如何做到呢?

      对于函数开放封闭原则,我们一般不允许修改。所以我们引入了装饰器:

    def outer(func):  
      def inner():
        print("添加在原函数之前")
        r = func()    #保留原函数的返回值
        print('添加在原函数之后')
        return r       #将保留的返回值返回回去
      return inner
     
    @outer             #等价于f1 = outer(f1)
    def f1():
        print("F1")
     
    def f2():
        print("F2")
     
    def f3():
        print("F3")
         
    def f4():
        print("F4")
         
    f1()                #执行函数,f1()已经等价于inner()了

    二.简单装饰器的流程剖析


    三.带参数的装饰器

    3.1

    #一般装饰器,不能装饰有参数的函数
    def outer(func):  #func为待装饰的函数
        def inner():  #从上往下执行,遇到def inner,就将函数扔进内存空间,但不执行
            print("执行原函数前添加的部分")
            r = func() #接收原函数的返回值
            print("执行原函数后添加的部分")
            return r   #返回原函数的返回值
        return inner  #返回inner给index
         
         
     
    @outer             #index = outer(index)
    def index():
        print("非常复杂的功能")
        return True
         
     
    index()

    3.2:修改方案:根据参数的个数,我们主要得修改装饰器的内层函数

    #如果待包装函数有参数
    #需要如何修改装饰器呢
    def outer(func): 
        def inner(a1, a2): 
            print("执行原函数前添加的部分")
            r = func(a1, a2)
            print("执行原函数后添加的部分")
            return r  
        return inner 
         
         
     
    @outer           
    def index(a1, a2):
        print("非常复杂的功能")
        return a1 + a2
         
    @outer
    def home(s1, s2):
        print("非常复杂的功能")
        return "HOME"
         
     
    ret1 = index(1, 2)  #应用了装饰器之后index变成装饰器的内层函数了
                  
     
    ret2 = home(1, 2)  

    3.3:但是,如果不同的待装饰函数的参数个数不一致该怎么办呢?

    修改方案:使用动态参数,*arg**kwargs扩大接收参数的形式。

    def outer(func): 
        def inner(*arg ,**kwargs): 
            print("执行原函数前添加的部分")
            r = func(*arg ,**kwargs)  #内部让*argj元组或**kwargs字典吐出参数,传入原函数
            print("执行原函数后添加的部分")
            return r  
        return inner 
         
    @outer
    def home(s1):       #一个参数
        print("非常复杂的功能")
        return "HOME"
     
    @outer           
    def index(a1, a2):  #两个个参数
        print("非常复杂的功能")
        return "INDEX"
     
    @outer
    def show(x1, x2, x3):#三个参数
        print("非常复杂的功能")
        return "SHOW"
     
         
    ret1 = home(1)
     
    ret2 = index(1, 2)          
     
    ret3 = show(1, 2, 3)       

    四.使用多装饰器装饰一个函数

    应用场景:例如有100个函数,其中10个函数需要加上一部分功能,

    而另外90个函数还需要加上额外得一部分功能,怎么做?

    方法一

    def outer0(func): 
        def inner(*arg ,**kwargs): 
            print("执行原函数前添加的部分")
            r = func(*arg ,**kwargs)
            print("执行原函数后添加的部分")
            return r  
        return inner 
         
    def outer1(func): 
        def inner(*arg ,**kwargs): 
            print("执行原函数前添加的部分(额外)")
            print("执行原函数前添加的部分")
            r = func(*arg ,**kwargs) 
            print("执行原函数后添加的部分")
            return r  
        return inner 
         
         
    @outer0   #功能1
    def home(s1):     
        print("非常复杂的功能")
        return "HOME"
     
    @outer0  #功能1       
    def index(a1, a2):
        print("非常复杂的功能")
        return "INDEX"
     
     
    @outer1  #功能2
    def show(x1, x2, x3):
        print("非常复杂的功能")
        return "SHOW"
     
         
    ret1 = home(1)
     
    ret2 = index(1, 2)          
     
    ret3 = show(1, 2, 3)

    缺点:装饰器outer2的代码与outer的代码有重复的部分,我们应该

    尽量避免重复代码

    方法二:改进版

    def outer1(func): 
        def inner(*arg ,**kwargs): 
            print("执行原函数前添加的部分(1)")
            r = func(*arg ,**kwargs)
            print("执行原函数前添加的部分(4)")    
            return r  
        return inner 
         
    def outer0(func): 
        def inner(*arg ,**kwargs): 
            print("执行原函数前添加的部分(2)")
            r = func(*arg ,**kwargs) 
            print("执行原函数后添加的部分(3)")
            return r  
        return inner
     
    @outer0
    def home(s1):    
        print("非常复杂的功能")
        return "HOME"
         
    @outer1   #先执行这个函数的装饰功能
    @outer0   #再执行这个函数的装饰功能
    def index(a1, a2): 
        print("非常复杂的功能")
        return "INDEX"
     
         
    ret1 = home(1)
    ret2 = index(1, 2)

    多重装饰器流程分析:(原函数的两次变化)

      没应用装饰器之前,原函数就是原函数

      应用第一个装饰器(outer0))之后,原函数变成了outer0函数的内层函数了,由func保留了原函数

      应用第二个装饰器(outer1)之后,outer0的内层函数也就是此时的原函数传入了第二个装饰器里面

    去了,替换成第二个装饰器的内存函数,并有第二个装饰器的参数func保存了原函数。

    装饰过程


    执行过程


    装饰次序

    #多层装饰器的流程
    #第一个装饰器分别装饰第一层和最后一层
    #第二个装饰器分别装饰第二层和倒数第二层
    #第三个装饰器分别装饰第三层和倒数第三层
    #以此类推,中间放要装饰的函数

     五.装饰器的应用

      单层装饰器:比如京东的网页,在进入我的购物车之前需要登录,这个登录就是一个装饰器

      多层装饰器:对于京东的用户来说,有大家公共的页面,也有对于钻石vip和白金vip不同的

            页面,所以在使用第一层登录装饰器之后,还需要加上额外的用户权限的装饰器

     

  • 相关阅读:
    hospital 基于反射的 在线医疗项目(三)
    hospital 基于反射的 在线医疗项目(二)
    【前端笔记】之 消息提示框
    hospital 基于反射的 在线医疗项目(-)
    【前端笔记】之一个简单好看的的下拉菜单 :select下拉框
    Dubbo和Zookeeper在Linux系统的安装
    记录一下Java String类的常用方法
    myeclipse与tomcat、jdk的安装和配置
    jQuery选择器总结
    js根据2个日期计算相差天数
  • 原文地址:https://www.cnblogs.com/Acekr/p/7376444.html
Copyright © 2011-2022 走看看