• 装饰器总结


    1. 开放封闭原则

      • 对拓展是开放的,允许代码拓展,添加新功能
      • 对修改是封闭的,不能修改函数的源码和调用方式
    2. 装饰器

      • 在不改变原被装饰函数的源代码以及调用方式的前提下,为其添加额外的功能
      # 版本一,测试每个函数都要写一遍代码.
      import time
      def func1():
          time.sleep(2)    # 暂停2秒
          print('测试延迟')
      time1 = time.time()  # 返回的格林尼治时间,是此时此刻距离1970年1月1日0时0分0秒的时间秒数.也叫时间戳
      func1()
      time2 = time.time()
      print(time2 - time1)
      
      # 版本二,只能测试特定的函数
      import time
      def func1():
          time.sleep(2)    
          print('测试延迟')
      
      def ceshi():
          time1 = time.time()  
          func1()
          time2 = time.time()
          print(time2 - time1)
      ceshi()
      
      # 版本三,虽然没有改变原函数代码,但是改变了执行方式,不符合开放封闭原则
      import time
      def func1():
          time.sleep(2)    
          print('测试延迟')
      def ceshi(func):
          time1 = time.time() 
          func()
          time2 = time.time()
          print(time2 - time1)
      ceshi(func1)
      
      # 版本四,实现真正的开放封闭原则:装饰器
      import time
      def func1():
          time.sleep(2)
          print('测试延迟')
      
      def timer(func):
          def ceshi():
              time1 = time.time()
              func()
              time2 = time.time()
              print(time2 - time1)
          return ceshi
      func1 = timer(func1)
      func1()
      
      # 带返回值的装饰器
      import time
      def func1():
          time.sleep(2)
          print('测试延迟')
          return '测试成功'
      
      def timer(func):
          def ceshi():
              time1 = time.time()
              ret = func()
              time2 = time.time()
              print(time2 - time1)
              return ret
          return ceshi
      func1 = timer(func1)
      print(func1())
      
      # 被装饰函数带参数的装饰器
      import time
      def func1(name):
          time.sleep(2)
          print(f'{name}测试延迟')
          return f'{name}测试成功'
      
      def timer(func):
          def ceshi(name):
              time1 = time.time()
              ret = func(name)
              time2 = time.time()
              print(time2 - time1)
              return ret
          return ceshi
      func1 = timer(func1)
      print(func1('太上老君'))
      
      # 被装饰函数不定参数的装饰器
      import time
      def func1(*args, **kwargs):
          time.sleep(2)
          print(f'{args}测试延迟')
          print(f'{kwargs}测试延迟')
          return f'{args, kwargs}测试成功'
      
      def timer(func):
          def ceshi(*args, **kwargs):
              time1 = time.time()
              ret = func(*args, **kwargs)
              time2 = time.time()
              print(time2 - time1)
              return ret
          return ceshi
      func1 = timer(func1)
      print(func1('太上老君', '元始天尊', 我叫='通天教主'))
      
      # 标准的装饰器:语法糖
      import time
      def timer(func):
          def ceshi(*args, **kwargs):
              time1 = time.time()
              ret = func(*args, **kwargs)
              time2 = time.time()
              print(time2 - time1)
              return ret
          return ceshi
      @timer   #  相当于 func1 = timer(func1),没有特殊意义,为了简单化
      def func1(*args, **kwargs):
          time.sleep(2)
          print(f'{args, kwargs}测试延迟')
          return f'{args, kwargs}测试成功'
      print(func1('太上老君', '元始天尊', 我叫='通天教主'))
      
      # 带参数的装饰器
      # 准备好qq文件用于保存qq密码,tiktok用于保存抖音密码
      def get_dic(file_name): # 获取密码库
          dic = {}
          with open(file_name, mode='r', encoding='utf-8') as f1:
              for line in f1:
                  username, psw = line.strip().split('|')
                  dic[username] = psw
          return dic
      
      def login(dic):   # 3次登陆功能
          time = 3
          while time > 0:
              username = input('请输入用户名:').strip()
              psw = input('请输入密码:').strip()
              if dic.get(username) == psw:
                  return True
              time -= 1
          return False
      
      def wrapper_out(file_name):  # 装饰器本体
          def wrapper(func):
              def inner():
                  dic = get_dic(file_name) # 获取相应的密码库
                  if login(dic):  # 调用登陆函数
                      ret = func()
                      return ret
                  return False
              return inner
          return wrapper
      
      @wrapper_out('qq')
      def qq():
          print('欢迎登陆QQ~~~~')
          return '登陆成功'
      print(qq())
      
      @wrapper_out('tiktok')
      def tiktok():
          print('欢迎访问抖音~~~')
          return '登陆成功'
      print(tiktok())
      
      # 多个装饰器装饰同一个函数的运行顺序
      def w1(func):  # func == 原函数text
          def inner():
              print('正在运行w1.inner....1')  # 2
              func()  # 原函数text()
              print('正在运行w1.inner....2')  # 4
          return inner
      
      def w2(func):  # func == w1.inner
          def inner():
              print('正在运行w2.inner....1')  # 1
              func()  # w1.inner()
              print('正在运行w2.inner....2') # 5
          return inner
      @w2  #  text = w2(text)    后面的text是w1.inner, 前面的text == w2.inner
      @w1  #  text = w1(text)    后面的text是原函数, 前面的text == w1.inner
      def text():
          print('正在运行被装饰的函数...')  # 3
      
      text()  # w2.inner()
      
  • 相关阅读:
    1041. 困于环中的机器人
    95. 不同的二叉搜索树 II
    LeetCode945:使数组唯一的最小增量
    LeetCode:925.长按键入
    LeetCode:926. 将字符串翻转到单调递增
    InteliJ 安装PlantUML插件
    CodeBlock换肤
    正则表达式验证手机号和座机号
    C#中使用反射遍历一个对象属性和值以及百分数
    c#中@的用法
  • 原文地址:https://www.cnblogs.com/zyyhxbs/p/11077612.html
Copyright © 2020-2023  润新知