• 叠加装饰器和补充部分


    叠加装饰器

       叠加装饰器:
        在同一个被装饰对象中,添加多个装饰器,并执行。
        @装饰1
        @装饰2
        @装饰3
        def 被装饰对象():
            pass
        注意:装饰器在调用被装饰对象时才会执行添加新功能。
    
        - 叠加装饰器:
            - 装饰的顺序: 由下到上装饰
            - 执行的顺序: 由上往下
    注意:无论inner中出现让任何的判断,最后的都要返回”调用后的装饰对象“func(*args, **kwargs)
    
    def wrapper1(func):
        def inner1(*args, **kwargs):
            print('1---start')
            res = func(*args, **kwargs)#被装饰对象在调用时,如果还有其他inner,会先执行其他装饰器中的inner
            print('1---end')
            return res
        return inner1
    
    def wrapper2(func):
        def inner2(*args, **kwargs):
            print('2---start')
            res = func(*args, **kwargs)
            print('2---end')
            return res
        return inner2
    
    def wrapper3(func):
        def inner3(*args, **kwargs):
            print('3---start')
            res = func(*args, **kwargs)
            print('3---end')
            return res
        return inner3
    
    @wrapper1 #inner1 = wrapper1(inner2)
    @wrapper2 #inner2 = wrapper2(inner3)
    @wrapper3 #inner3 = wrapper3(index)
    def index():
        print('from the index>>>>>')
    index()
    >>>>>>>>>
    1---start
    2---start
    3---start
    from the index>>>>>
    3---end
    2---end
    1---end
    
    

    装饰器的分类

    # 无参装饰器: 装饰在被装饰对象时,没有传参数的装饰器。
    '''
    # 以下是无参装饰器
    @wrapper1  # inner1 = wrapper1(inner2)
    @wrapper2  # inner2 = wrapper2(inner3)
    @wrapper3
    '''
    
    # 有参装饰器: 装饰被装饰的对象时,有传参的装饰器
    在某些时候,我们需要给用户的权限进行分类
    '''
    # 以下是有参装饰器
    @wrapper1(参数1)  # inner1 = wrapper1(inner2)
    @wrapper2(参数2)  # inner2 = wrapper2(inner3)
    @wrapper3(参数3)
    '''
    
    def user_auth(user_role):
        '''
        有参装饰器函数
        '''
        
        def wrapper(func):
            def inner(*args, **kwargs):
                if user_role == 'vip':
                    print('welcome!')
                    res = func(*args, **kwargs)
                    return res
                elif user_role == '普通用户':
                    print('hi')
                    res = func(*args, **kwargs)
                    return res
            return inner
        return wrapper
    @user_auth('普通用户')  # wrapper = user_auth('普通用户')--->相当于@wrapper 语法糖
    
    def ndex():
        pass
    index()
    >>>>>>>
    hi
    
    wraps 的补充

    wraps :是一个修复工具,修复的是被装饰对象的空间

    from functools import wraps
    
    
    def wrapper(func):
        def inner(*args, **kwargs):
            '''
            此处是装饰器的注释
            :param func:
            :return:
            '''
            res = func(*args, **kwargs)
            return res
        return inner  # ---》 func
    
    
    @wrapper
    def index():
        '''
        此处是index函数的注释
        :return:
        '''
        pass
    
    
    print(index)  # 函数对象
    
    # 函数对象.__doc__: 查看函数内部的注释
    print(index.__doc__)  # inner.__doc__
    >>>>>>>
    <function wrapper.<locals>.inner at 0x000002A0A52A7C80>
    
            此处是装饰器的注释
            :param func:
            :return:
    
    

    下面是使用了wraps后的 修复被装饰对象空间,下面是被装饰对象的注释

    def wrapper(func):
     
        @wraps(func)  # 修改名称空间: inner ---》 func  此处修改成功
        def inner(*args, **kwargs):   
            '''
            此处是装饰器的注释
            :param func:
            :return:
            '''
            res = func(*args, **kwargs)
            return res
        return inner  # ---》 func
    
    
    @wrapper
    def index():
        '''
        此处是index函数的注释
        :return:
        '''
        pass
    
    
    print(index)  # 函数对象
    
    # 函数对象.__doc__: 查看函数内部的注释
    print(index.__doc__)  # inner.__doc__
    >>>>>>>>>>>>
    <function index at 0x00000199BCC77C80>
    
        此处是index函数的注释
        :return:
        
    

    编写装饰器 为多个函数加上认证的功能(用户的账号i密码来源于文件)要求登录一次,后续的函数无需再输入用户名和密码。

    # 可变类型,无需通过global引用,可直接修改
    user_info = {
        'user': None  # username
    }
    
    # 不可变类型,需要在函数内部使用global对其进行修改
    user = None
    
    def login():
        # 判断用户没有登录时,执行
        # 登录功能
        # global user
        username = input('请输入账号: ').strip()
        password = input('请输入密码: ').strip()
        with open('user.txt', 'r', encoding='utf-8') as f:
            for line in f:
                print(line)
                name, pwd = line.strip('
    ').split(':')  # [tank, 123]
    
        if username == name and password == pwd:
            print('登录成功!')
            user_info['user'] = username
        else:
            print('登录失败!')
    
    
    def login_auth(func):  # func ---> func1, func2, func3
        def inner(*args, **kwargs):
            # 已经登录,将被装饰对象直接调用并返回
            if user_info.get('user'):
                res = func(*args, **kwargs)  # func() ---> func1(), func2(), func3v
                return res
    
            # 若没登录,执行登录功能
            else:
                print('请先登录...')
                login()
    
        return inner
    
    
    # func1,2,3 都需要先登录才可以使用,若登录一次,
    # 后续功能无需再次登录,绕过登录认证
    @login_auth
    def func1():
        print('from func1')
        pass
    
    
    @login_auth
    def func2():
        print('from func2')
        pass
    
    
    @login_auth
    def func3():
        print('from func3')
        pass
    
    
    while True:
        func1()
        input('延迟操作...')
        func2()
        func3()
    >>>>>>>>>>>>>
    请输入你的账户:david
    请输入你的密码:123
    登录成功
    {'user': 'david'}
    from func1
    延迟操作
    from func2
    from func3
    from func1
    延迟操作
    
    
    # 无参装饰器模板
    def wrapper(func):
        def inner(*args, **kwargs):
            res = func(*args, **kwargs)
            # 在被装饰对象调用后添加功能
            return res
        return inner
    
    
    # 有参装饰器模板
    def outer(arg):
        def wrapper(func):
            def inner(*args, **kwargs):
                res = func(*args, **kwargs)
                return res
    
            return inner
        return wrapper
    
  • 相关阅读:
    ●BZOJ 2669 [cqoi2012]局部极小值
    ●HDU 6021 MG loves string
    试试数学公式~
    ●BZOJ 3622 已经没有什么好害怕的了
    ●BZOJ 2560 串珠子
    ●BZOJ 4361 isn
    ●BZOJ 2393 Cirno的完美算数教室
    ●BZOJ 1042 [HAOI2008]硬币购物
    ●BZOJ 2839 集合计数
    【LG2481】[SDOI2011]拦截导弹
  • 原文地址:https://www.cnblogs.com/bs2019/p/11858648.html
Copyright © 2020-2023  润新知