装饰器

装饰器

【一】什么是装饰器

  • 装饰 代指为被装饰对象添加新的功能代指器具/工具,装饰器与被装饰的对象均可以是任意可调用对象。
  • 概括地讲,装饰器的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。
  • 装饰器经常用于有切面需求的场景
    • 插入日志、性能测试、事务处理、缓存、权限校验等应用场景
    • 装饰器是解决这类问题的绝佳设计
    • 有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

【二】装饰器的作用

  • 软件的设计应该遵循开放封闭原则,即对扩展是开放的,而对修改是封闭的。
    • 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
    • 对修改封闭,意味着对象一旦设计完成,就可以独立完成其工作,而不要对其进行修改。
  • 软件包含的所有功能的源代码以及调用方式,都应该避免修改,否则一旦改错,则极有可能产生连锁反应,最终导致程序崩溃
    • 而对于上线后的软件,新需求或者变化又层出不穷,我们必须为程序提供扩展的可能性,这就用到了装饰器。

【三】装饰器的分类

  • 函数装饰器分为:无参装饰器和有参装饰两种
  • 二者的实现原理一样,都是’函数嵌套+闭包+函数对象’的组合使用的产物。

【四】举例

  • 闭包的使用

    def fun():
        print(f"这是fun开始")
        def inner():
            print("这是inner")
        print(f"这是fun的结束")
        #返回一个inner
        return inner
    #inner函数赋值给inner
    inner=fun()
    inner()
    
  • time.time()的使用

    import time
    def fun(func):
        start_time=time.time()
        res=func()
        print(f'总耗时 {time.time() - start_time} s')
        return True,res
    
    def function():
        print("时长为:")
        return '完成'
    #把function作为参数传递给fun函数
    result=fun(function)
    print(result)
    #输出:
    时长为:
    总耗时 0.0 s
    (True, '完成')
    
    • 登录权限案例

      login_user_dict = {'username': 'tony', 'is_admin': True}
      user_data_dict = {'tony': {'password': 123, 'role': 'admin'},
                        'hope': {'password': 789, 'role': 'normal'}}
      
      
      def check_admin(func):
          def inner(login_user_dict):
              # 验证当前是否登录并且是管理员
              if login_user_dict['username'] and login_user_dict['is_admin']:
                  # 如果是管理员 ,就正常执行我传进来的函数地址
                  res = func(login_user_dict)
                  return res
              # 重新校验
              else:
                  # 重新登录的逻辑
                  return False, '重新登录'
          return inner
      @check_admin
      def get_money(login_user_dict):
          # 取钱的前提是 : 我已经登陆过并且是管理员 ---> 验证我的登录和我的身份
          return True, f'{login_user_dict["username"]} 取了一万块'
      print(get_money(login_user_dict))
      
      
      def check_admin(func):
          def inner(*args, **kwargs):
              # 验证我当前是否登录并且是管理员
              if login_user_dict.get('username') and login_user_dict.get('is_admin'):
                  # 如果是管理员,就正常执行我传进来的函数地址
                  res = func(*args, **kwargs)
                  return True, res
              # 重新校验
              else:
                  # 重新登录的逻辑
                  return False, '重新登录'
          return inner
      
      @check_admin
      def login(username, password):
          if password == user_data_dict[username].get('password'):
              print(f'登录成功!')
          if user_data_dict[username].get('role') == 'admin':
              login_user_dict['is_admin'] = True
          else:
              login_user_dict['is_admin'] = False
          return username, password
      
      result = login('tony', '123')
      print(result)
      #(True, ('tony', '123'))
      

【五】无参装饰器模板

 def add():
     return 1
 def outer(func):
     def inner():
#         '''这里写调用 func 函数之前的逻辑'''
         res = func()
#         '''这里写调用 func 函数之后的逻辑'''
        return res
    return inner
 add = outer(func=add)
 add()

【六】带参装饰器模板

def outer(func):
    def inner(*args,**kwargs):
        '''这里写调用 func 函数之前的逻辑 '''
        res = func(*args,**kwargs)
        '''这里写调用 func 函数之后的逻辑'''
        return res
    return inner
@outer
def add(*args,**kwargs):
    print(args)
    print(kwargs)
user_data_dict = {'username': 'tony', 'age': 16}

def see(func):
    def inner(*args, **kwargs):
        if user_data_dict['age'] >= 18:
            res = func(*args, **kwargs)
            return res
        else:
            print(f'不能看电影')
    return inner

@see
def watch():
    print(f'可以看电影')

watch()
posted @ 2023-12-11 18:22  -半城烟雨  阅读(13)  评论(0编辑  收藏  举报