ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

装饰器应用

2021-07-05 21:33:55  阅读:121  来源: 互联网

标签:index name wrapper 应用 time print 装饰 def


内容概要

  • 装饰器定义
  • 装饰器
    • 推导过程
    • 语法糖
  • 有参装饰器
  • 叠加多个装饰器

内容详解

  • 装饰器定义

    # 1.什么是装饰器
    	# 器指的是工具,可以定义成函数
        # 装饰指的是为其他事物添加额外的东西点缀
        # 装饰器指定义一个函数,该函数时用来为其他函数添加额外的功能
    # 2.为何要用装饰器
    	# 开放封闭原则:
        	# 开放:指的是对拓展功能是开放的
            # 封闭:指的是对修改源代码是封闭的
            
        # 装饰器就是不修改被装饰器对象的源代码和调用方式
    
  • 装饰器

    • 推导过程

      # 源代码
         import time
         def index(x,y):
             time.sleep(3)
             print('index %s %s'%(x,y))
         index(1,2)
          
      # 需求:计算源代码运行时间,不修改源代码以及调用方式
      # 方案一:没有修改调用方式,但是修改了源代码
          import time
          def index(x,y):
              start = time.time()
              time.sleep(3)
              print('index %s %s'%(x,y))
              stop = time.time()
              print(stop - start)
          index(1,2)
          
      # 方案二:没有修改源代码,也没修改调用方式,但是代码冗余
          import time
          def index(x,y):
              time.sleep(3)
              print('index %s %s'%(x,y))
          start = time.time()    
          index(1,2)
          stop = time.time
          print(stop - start)
          
          start = time.time()    
          index(2,3)
          stop = time.time
          print(stop - start)
          
      # 方案三:没有修改源代码,也没代码冗余,但是修改了调用方式
      	import time
          def index(x,y):
              time.sleep(3)
              print('index %s %s'%(x,y))
          # 将冗余的代码定义成函数,解决了代码冗余的问题    
          def wrapper(*args,**kwargs):  # 同时用*args,**kwargs,将本来写死的index写活
              start = time.time()    
              index(*args,**kwargs)
              stop = time.time
              print(stop - start) 
          wrapper(1,2)
          
      # 方案四:在方案三的既基础上不改变函数的调用方式
          import time
          def index(x,y):
              time.sleep(3)
              print('index %s %s'%(x,y))
              # print(index)  # <function index at 0x000002430182F160>
          def outter(func):
              # func = index  # 直接将func当作形参给outter函数
              def wrapper(*args,**kwargs):  
                  start = time.time()    
                  func(*args,**kwargs)
                  # 这里本来是index(),但是这样就写死了,用闭包函数将其写活
                  stop = time.time
                  print(stop - start) 
               return wrapper
          	# 为何要return wrapper? 因为本来wrapper是全局的,闭包函数后,wrapper又变成局部的了,这里用return将wrapper使其变成全局的
          f = outter(func) # 即f = outter(index)
          # f = 当成那个wrapper函数的内村地址
          index = outter(index)  # 这里实际是调了outter得到一个返回值给了index
          # f本来就是个变量名可以直接换成index,但是要注意这里的变量名index和内存地址index是两个概念,只是为了不改变调用方式,以假乱真
          # 同时这里outter(index) = wrapper的内存地址,实际就是wrapper()变成了index()
          # print(index)  # <function outter.<locals>.wrapper at0x0000024301CDC4C0>
          # 可以从两个print(index)输出的结果直观的看出区别
          index(1,2)
          
      # 方案五:在方案三的基础上把装饰器写活了,原来只能装饰index
      	import time
          def index(x,y):
              time.sleep(3)
              print('index %s %s'%(x,y))
          def home(name):
              time.sleep(2)
              print('welcome %s to home page'%name)
              return name
          def outter(func):
              def wrapper(*args,**kwargs):
                  start = time.time()
                  func(*args,**kwargs)
                  stop = time.time()
                  print(stop-start)
                   
              return wrapper
          index = outter(index)
          index(1,2)
          home('ycc') # 但是这里拿不到home函数的返回值
          
      # 方案六:将wrapper做的跟被装饰对象一摸一样,以假乱真
      	def index(x, y):
          time.sleep(3)
          print('index %s %s' % (x, y))
      
          def home(name):
              time.sleep(2)
              print('welcome %s to home page' % name)
              return name
          def outter(func):
              def wrapper(*args, **kwargs):
                  start = time.time()
                  res = func(*args, **kwargs)
                  stop = time.time()
                  print(stop - start)
                  return res
          # 这里返回res,就是为了能够在最后得到return name的返回值(即home的返回值),而不是None,做到真正的偷梁换柱
              return wrapper
      
          home = outter(home)  # 括号里的home = wrapper的内存地址
          index = outter(index)  # 括号里的index = wrapper的内存地址
          # 这里的两个wrapper的功能是一样的,但是两个内存地址是不一样的,分别是用来装饰index和home的内存地址
          index(1, 2)
          # home('ycc')
          res = home('ycc')  # res = wrapper('ycc') 这里其实是偷梁换柱将wrapper换成了home,所以返回值为None
          print('name 返回值--》',res)
                  
      	
              
      

      67..

    • 语法糖

      import time 
      # 装饰器
      def outter(func):  # 一定要将装饰器函数放在 @装饰器 上方,不然会报错,因为找不到
          def wrapper(*args,**kwargs):
              start = time.time()
              res = func(*args,**kwargs)
              stop = time.time()
              print(stop - start)
              return res
          return wrapper
      @outter # 等价于:index = outter(index)
      def index(x,y):
          time.sleep(3)
          print('index %s %s'%(x,y))
      @outter # 等价于:home = outter(home)
      def home(name):
          time.sleep(2)
          print('welcome %s to home page'%name)
          return name
      	
      index(1,2)
      res = home('ycc')
      print('返回值--》',res)
      
  • 有参装饰器

    # 由于语法糖@的限制,outter函数只能有一个参数,并且该参数只用来接受被装饰对象的内存地址
    #  偷梁换柱后
    # index的参数什么样子,wrapper的参数就应该什么样子
    # index的返回值什么样子,wrapper的返回值就应该什么样子
    # index的属性什么样子,wrapper的属性就应该什么样子
    
    # 加验证功能
    # 1.山炮方案一:
    	def auth(func,db_type):
            def wrapper(*args,**kwargs):
                name = input('name is :').strip()
                pwd = input('pwd is :').strip()
                if db_type == 'file':
                    print('基于文件验证')
                    if name == 'ycc' and pwd == '1217':
                        res = func(*args,**kwargs)
                        return res
                    else:
                        print('name or pwd error')
                elif db_type == 'mysql':
                    print('基于数据库验证')
                elif db_type == 'ldap':
                    print('基于ldap验证')
                else:
                	print('不支持该验证')
            return wrapper
         def index(x,y):
             print('index-->%s %s'%(x,y))
        
         def home(name):
             print('welcome %s to home page'%name)
        
         def transfer():
             print('transfer')
        
         index = auth(index,'file')
         home = auth(home,'mysql')
         transfer = auth(transfer,'ldap')
        
         index(1,2)
         home('ycc')
         transfer()
            
    # 2.山炮方案二:基于方案一用闭包函数
         def auth(db_type):
             def deco(func):
                 def wrapper(*args,**kwargs):
                     name = input('name is :').strip()
                     pwd = input('pwd is :').strip()
                     if db_type == 'file':
                         print('基本文本验证')
                         if name == 'ycc' and pwd == '123':
                             print('login successful')
                         else:
                             print('name or pwd error')
                             res = func(*args,**kwargs)
                             return res
                     elif db_type == 'mysql':
                        print('基于数据库验证')
                     elif db_type == 'ldap':
                         print('基于ldap验证')
        
                 return wrapper
             return deco
        
         deco = auth(db_type='file')
         @deco
         def index(x,y):
             print('index-->%s %s'%(x,y))
        
         deco = auth(db_type='mysql')
         @deco
         def home(name):
             print('welcome %s to home page'%name)
             return name
         deco = auth(db_type='ldap')
         @deco
         def transfer():
             print('transfer')
        
         index(1,2)
         home('haha')
         transfer()
            
    # 正宗解决方案:语法糖
        def login():
            name = input('name is :').strip()
            pwd = input('pwd is :').strip()
    
            if name == 'ycc' and pwd == '123':
                print('login successful')
            else:
                print('name or pwd error')
    
        def auth(db_type):
            def deco(func):
                def wrapper(*args,**kwargs):
    
                    if db_type == 'file':
                        login()
                        print('基于文件验证')
                        # res = func(*args,**kwargs)
                        # return res
                    elif db_type == 'mysql':
                        login()
                        print('基于数据库验证')
                        # res = func(*args, **kwargs)
                        # return res
    
                    elif db_type == 'ldap':
                        login()
                        print('基于ldap验证')
                        # res = func(*args, **kwargs)
                        # return res
                    res = func(*args, **kwargs)
                    return res
                return wrapper
            return deco
    
        @auth(db_type='file')
        def index(x,y):
            print(x,y)
    
        @auth(db_type='mysql')
        def home(name):
            # print('welcome %s to home page'%name)
            print(f'welcome {name} to home page')
            return name
    
        @auth(db_type='ldap')
        def transfer():
            print('transfer')
    
    
        index(1, 2)
        name = home('ycc')
        print(name)
        transfer()
    
  • 叠加多个装饰器

    def deco1(func1):  # func1 = wrapper2的内存地址(即正下方函数的内存地址)
        def wrapper1(*args,**kwargs):
            print('正在运行===>deco1.wrapper1')
            res1 = func1(*args,**kwargs)
            return res1
        return wrapper1
    
    def deco2(func2):  # func2 = wrapper3的内存地址 (即正下方函数的内存地址)
        def wrapper2(*args,**kwargs):
            print('正在运行===>deco2.wrapper2')
            res2 = func2(*args,**kwargs)
            return res2
        return wrapper2
    
    def deco3(x):
        def outter3(func3):  # func3 = 被装饰对象函数index的内存地址(即正下方函数的内存地址)
            def wrapper3(*args,**kwargs):
                print('正在运行===>deco3.outter3.wrapper3')
                res3 = func3(*args,**kwargs)
                return res3
            return wrapper3
        return outter3
    
    # 加载顺序:自下而上
    @deco1
    #index = deco1(wrapper2)==>调deco1(wrapper2)得:这里的返回值wrapper1==>即index = wrapper1得内存地址
    @deco2
    # index = deco2(wrapper3)==>调deco2(wrapper3)得:这里的返回值wrapper2==>即index = wrapper2的内存地址
    #deco2会将正下方的函数的内存地址当作参数传过来用
    @deco3(111)
    # 由有参装饰器得==》outter3=deco3(111)==>index=outter3(index)==>调outter3(index)得:这里返回值wrapper3==>即index = wrapper3的内存地址
    #                         outter3会将正下方的函数的内存地址当作参数传过来,这里即index的内存地址
    def index(x,y):
        print('index--》%s:%s'%(x,y))
    
    # 执行顺序:自上而下  wrapper1=》wrapper2=》wrapper3
    index(1,2)
    
    
    

标签:index,name,wrapper,应用,time,print,装饰,def
来源: https://www.cnblogs.com/lyz666/p/14974456.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有