• 第二十九篇 装饰器


    第二十九篇 装饰器

    一、无参装饰器

    1.什么是装饰器

    • 1.修改或增加其他函数的功能的函数
    • 2.需要注意的是:
      • 1.装饰器本身是可以被任意调用的对象
      • 2.装饰的对象也可以是任意可调用的对象

    2.为什么需要装饰器

    当我们需要修改程序的某个功能,但是不想修改函数或对象的调用方法时,这时就可以使用装饰器。由于软件的维护需要遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能是开放的

    3.如何使用装饰器

    • 1.装饰器的实现必须遵循两大原则(装饰器就是在遵循以下两个原则的前提下为被装饰对象添加新功能):

      # 假设源码是一个延时函数
      import time
      def timesleep():
          time.sleep(1)
          print('睡眠一秒')
      
      • 1.不修改被装饰对象的源代码
      # 改源码增加功能
      import time
      def counttime():
          start = time.time()
          time.sleep(1)
          print('睡眠一秒')
          end = time.tiem()
      	pirnt(end-start)
      
      • 2.不修改被装饰对象的调用方法
      # 改变调用方法
      import time
      def timesleep():
          time.sleep(1)
          print('睡眠一秒')
      
      def counttime():
          start = time.time()
          timesleep()
          end = time.tiem()
      	pirnt(end-start)
      
    • 利用装饰器实现

    # 源码
    import time
    def timesleep():
        time.sleep(1)
        print('睡眠一秒')
    
    # 装饰器
    def deco(func):
        def wrapper():
    		start = time.time()
        	func()
        	end = time.tiem()
    		pirnt(end-start)
    	return wrapper
    
    # 定义变量接收返回值
    timesleep = deco(timesleep)
    timesleep()
    

    4.完善装饰器

    • 上述的装饰器,最后调用timesleep()的时候,其实是在调用wrapper(),因此如果原始的timesleep()有返回值的时候,wrapper()函数的返回值应该和timesleep()的返回值相同,也就是说,我们需要同步原始的timesleep()和wrapper()的返回值
    # 源码
    import time
    def timesleep():
        time.sleep(1)
        print('睡眠一秒')
    	return 666
    
    # 装饰器
    def deco(func):
        def wrapper():
    		start = time.time()
        	res = func()
        	end = time.tiem()
    		pirnt(end-start)
            return res
    	return wrapper
    
    # 定义变量接收返回值
    timesleep = deco(timesleep)
    res = timesleep()
    print(res)
    
    • 如果原始的timesleep()函数需要传参,那么我们之前的装饰器是无法实现该功能的,由于有wrapper() = timesleep(),所以给wrapper()函数传参即可
    # 源码
    import time
    def timesleep(*args,**kwargs):
        time.sleep(1)
        print('睡眠一秒')
        print(args,kwargs)
    	return 666
    
    # 装饰器
    def deco(func):
        def wrapper(*args,**kwargs):
    		start = time.time()
        	res = func(*args,**kwargs)
        	end = time.tiem()
    		pirnt(end-start)
            return res
    	return wrapper
    
    # 定义变量接收返回值
    timesleep = deco(timesleep)
    res = timesleep(2,3,3,66,name='king',age=20)
    print(res)
    

    5.装饰器语法糖

    • 在被装饰函数正上方,并且是单独一行写上@装饰器名
    # 源码
    import time
    
    # 装饰器
    def deco(func):
        def wrapper(*args,**kwargs):
    		start = time.time()
        	res = func(*args,**kwargs)
        	end = time.tiem()
    		pirnt(end-start)
            return res
    	return wrapper
    
    @deco
    def timesleep(*args,**kwargs):
        time.sleep(1)
        print('睡眠一秒')
        print(args,kwargs)
    	return 666
    
    res = timesleep(2,3,3,66,name='king',age=20)
    print(res)
    

    6.装饰器模板

    def deco(func):
        def wrapper(*args,**kwargs):
            res = func(*args,**kwargs)
            return res
        return wrapper
    

    二、有参装饰器

    1.三层闭包

    • 由于两层的装饰器,参数必须得固定为 func ,但三层的装饰器解除了这个限制,我们不仅可以使用上述单个参数的三层装饰器,多个参数的只需要在三层装饰器中多加入几个参数即可。也即是说,三层装饰器已经够用,在多一层已是多余
    is_login_dic = {'username':None}
    
    def auth(origin):
        def login_deco(func):
            def wrapper(*args,**kwargs):
                if origin == 'file':
                    if not is_login_dic['username']:
                        username = input('请输入注册用户名:').strip()
                        if username != 'king':
                            print('非法登陆')
                            return
                        is_login_dic['username'] = username
                        res = func(*args,**kwargs)
                        return res
                    else:
                        res = func(*args,**kwargs)
                        return res
    			elif origin == 'mysql':
                    print('非法登陆')
    			else:
                    print('登陆失败')
    		return wrapper
        return login_deco
    
    # f = origin('file')  
    # shopping = f(shopping)
    # shopping()
    
    @auth('file')
    def shopping():
        print('欢迎光临')
        
    @auth('mysql')
    def withdraw():
        print('欢迎提现')
    
  • 相关阅读:
    Java生成二维码连接
    Spring boot 整合 Elasticsearch
    Windows下安装ElasticSearch
    springcloud zookeeper+gateway
    idea中Springcloud同时运行多个模块、微服务
    【转】为什么我的DIV块前总有空隙?
    【转载】通过JSFL让Flash Professional CS4或CS5拥有批量FLA导出SVG的功能
    jQuery Mobile中的页面加载与跳转机制
    关于Conversion to Dalvik format failed with error 1错误
    带权重的随机输出数组中的元素
  • 原文地址:https://www.cnblogs.com/itboy-newking/p/10958983.html
Copyright © 2020-2023  润新知