ITPub博客

首页 > 数据库 > 数据库开发技术 > python装饰器的组合和装饰器返回值

python装饰器的组合和装饰器返回值

原创 数据库开发技术 作者:程序员小钟同学 时间:2021-03-31 16:15:00 0 删除 编辑

1 有返回值的装饰器

首先需要知道装饰器的

  • 本质是一个函数,它把被装饰的函数作为位置参数传递。

  • 被装饰的函数变为一个参数,装饰器内部可以使用它来执行某些操作,然后返回一个函数引用,这个函数可以是原始函数,或者是另外一个函数,或者是一个你需要传递的值。

  • 执行原有函数(被装饰的函数)的同时,再加上一些额外的功能,所以我们可以再此基础上增加返回值

在我们的flask中,有些时候,可能经过相关装饰器处理之后,需要传递一个返回值到我们的被装饰器的函数里面,那就是需要一个装饰器的返回值:

所以我们实现一个带有返回值的装饰器:

# 带参数且返回相关的值得装饰器
def check_required_back_parameter(token_key='X-Access-Token', nees_check_perms=None, is_log_operation=True):
    """
    :param token_key: 默认的头部的信息(提交的头部信息)
    :param nees_check_perms: 需要的权限标记
    :param is_log_operation: 是否需要记录日志
    :return:
    "
""
    def decorator(fn):
        @functools.wraps(fn)
        def wrapper(*args, **kwargs):
            # 头部提取的token信息进行校验
            token = get_heards_key(token_key)
            # print('token',token)
            if not token:
                # 从get里面进行提取
                form = SysPermissionForm().validate_for_api()
                if not form.token.data:
                    return InvalidTokenException()
                token = form.token.data
            # 验证TOEKN
            isok, state, token_result = jwt_helper.verify_bearer_token_state(secret=config_hepler.get('token', 'TOKEN_SECRETKEY'), token=token)
            # print('token_result', token_result)
            if not isok and state == 1:
                return InvalidTokenException()
            if not isok and state == 2:
                return ExpiredTokenException()

            # 验证用户有效性处理
            isok ,isstatus =  LogicSysUser.get_user_model_by_username(username=token_result.get('username'))
            # 用户状态(1-正常,2-冻结)
            if isstatus.get('status') == 2:
                return ForbiddenException()

            # 验证对应的接口的权限信息
            if nees_check_perms:
                # 权限标记
                permissions = token_result.get('permissions')
                if nees_check_perms not in permissions:
                    # 无权限
                    return ForbiddenException()

            # 如果需要记录日志的话,则开启相关的日志记录到数据库
            if is_log_operation:
                pass
                # LogiclogAction.addlog_model(user_id = token_result.get('user_id'), user_name=token_result.get('user_name'),operation = log_operation, ip =xutils.getip(),location =None,method =None,params =None, time =None)
            # 返回携带的参数信息
            return fn(token_result, *args, **kwargs)

        return wrapper

    return decorator

上面的示例中,我们经过相关逻辑处理后,最终返回了:fn(token_result, *args, **kwargs)

新增了一个token_result到我们的被装饰的函数上面。所以相关被装饰的函数,需要有一个对应的参数来接收:

# 获取到用户所属的权限菜单列表,并且组合好返回给前端
@app.route('/sys/permission/get_user_permission_by_token',method=['POST', 'GET', 'OPTIONS'])
@check_token.check_required_back_parameter() # 注意返回的参数信息需要放在第一个位置
def index(token_result):
    # 校验token是否存在
    print(token_result)
    # 校验token
    print(token_result.get('roles'))
    # 判断角色列表是否是多角色
    roles = token_result.get('roles')
    _result,_allAuth,_auth = None,None,None
    if roles and len(roles) <=1:
        # 单角色用户
        _,_result = LogicSysRolePermission.get_sys_role_permission_model_by_role_id(roles[0])
        print(_result)
        print(role_permission.bakc_main_menu(_result))
        _allAuth,_auth =role_permission.back_main_all_auth(_result)
    else:
        # 多角色用户
        pass

    data = {
        'menu':role_permission.bakc_main_menu(_result),
        'all_auth':_allAuth,
        'auth':_auth,
    }

    return Success(result=data, message='获取成功')

说明:

def index(token_result): 上面的token_result,是需要实现的,否则,因为我们的装饰器里新增了这个参数的传递。

ps:当然:其实上面示例不需要这么做,直接把我们的值给放在当前上下文请求对象动态新增一个新的属性就可以了!

2 装饰器函数再装饰一个装饰器函数(组合两个装饰器)

实验示例:

import functools


#新增一个函数内嵌我们的普通装饰器,且返回我们的普通的装饰器
def my_decorator(type=None):
    # 装饰器函数,参数 func 是被装饰的函数
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print("第一个装饰器-开始接收传入的参数:",type)
            print(func.__name__)
            print(func.__dict__)
            print('被装饰的函数的参数信息',func.__code__.co_cellvars)
            for key, data in kw.items():
                print('参数-> %s--值是:%s' % (key, data))
            # 真正执行的是这行。
            # func(*args, **kw)
            funcv= func(*args, **kw)

            return funcv
            # print('飞完之后,我给你找个飞机场!')
        return wrapper
    return decorator

# my_decorator.__code__.co_cellvars

#新增一个函数内嵌我们的普通装饰器,且返回我们的普通的装饰器
@my_decorator(type="我是第一个装饰器")
def my_decorator2(type=None,leishi="第二装饰器的参数测试"):
    # 装饰器函数,参数 func 是被装饰的函数
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print("第二个装饰器-开始接收传入的参数:",type)
            print(func.__name__)
            # 真正执行的是这行。
            # func(*args, **kw)
            funcv= func(*args, **kw)

            return funcv
            # print('飞完之后,我给你找个飞机场!')
        return wrapper
    return decorator

@my_decorator2(type="我是第二个装饰器,被第一个装饰器给装饰",leishi='第二装饰器的参数测试')
def ceshihanshu():
    print("我是最终被装饰的函数")

输出结果:

第一个装饰器-开始接收传入的参数: 我是第一个装饰器
my_decorator2
{}
被装饰的函数的参数信息 ('type',)
参数-> type--值是:我是第二个装饰器,被第一个装饰器给装饰
参数-> leishi--值是:第二装饰器的参数测试

从上面可以看,我们可以获取当被装饰器的装饰器的参数信息。

3 装饰器的合并(解决多个装饰器的时候一堆的问题)

import functools


def my_decorator_01(msg=None):
    # 装饰器函数,参数 func 是被装饰的函数
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            for key, data in kw.items():
                print('参数-> %s--值是:%s' % (key, data))

            # 函数的处理回调
            print('第1个装饰器--传入的参数', func.__name__)
            print('第1个装饰器--传入的参数', msg)
            print('第1个装饰器--start')
            funcv = func(*args, **kw)
            print('第1个装饰器--end')
            return funcv

        return wrapper

    return decorator


def my_decorator_02(msg=None):
    # 装饰器函数,参数 func 是被装饰的函数
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('第2个装饰器--传入的参数kw.items()', kw.items())

            for key, data in kw.items():
                print('参数-> %s--值是:%s' % (key, data))

            # 函数的处理回调
            print('第2个装饰器--传入的参数', func.__name__)
            print('第2个装饰器--传入的参数', msg)
            print('第2个装饰器--start')
            funcv = func(*args, **kw)
            print('第2个装饰器--end')
            return funcv

        return wrapper

    return decorator


def my_decorator_03(msg=None):
    # 装饰器函数,参数 func 是被装饰的函数
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('第3个装饰器--传入的参数kw.items()', kw.items())

            for key, data in kw.items():
                print('参数-> %s--值是:%s' % (key, data))

            # 函数的处理回调
            print('第3个装饰器--传入的参数', func.__name__)
            print('第3个装饰器--传入的参数', msg)
            print('第3个装饰器--start')
            funcv = func(*args, **kw)
            print('第3个装饰器--end')
            return funcv

        return wrapper

    return decorator


# 通过参数的里的元组(包含很多个装饰器)
def composed_decorator(*decorators, is_reversed=True):
    '''

    :param decs:
    :param is_reversed:  是否反转,True:表示按传入装饰器的顺序执行,False 表示反转
    :return:
    '
''

    def deco(fun):
        if is_reversed:
            # reverse(sequence) - >反转迭代器的序列值---列表的反转,就是逆序
            for dec in reversed(decorators):
                fun = dec(fun)
        else:
            for dec in decorators:
                fun = dec(fun)
        return fun

    return deco


@composed_decorator(my_decorator_01(msg="参数1"), my_decorator_02(msg='参数2'), is_reversed=True)
def ceshi_composed_decorator(a: str, b: str) -> str:
    return a + b


@composed_decorator(my_decorator_01(msg="参数1"), my_decorator_02(msg='参数2'), my_decorator_03(msg='参数3'))
def ceshi_composed_decorator(a: str, b: str) -> str:
    return a + b


print('合并装饰器', ceshi_composed_decorator('小钟', "同学"))

在flask中的应用:

# 通过参数的里的元组(包含很多个装饰器)
def composed_decorator(*decorators, is_reversed=True):
    '''

    :param decs:
    :param is_reversed:  是否反转,True:表示按传入装饰器的顺序执行,False 表示反转
    :return:
    '
''
    def deco(fun):
        if is_reversed:
            # reverse(sequence) - >反转迭代器的序列值---列表的反转,就是逆序
            for dec in reversed(decorators):
                fun = dec(fun)
        else:
            for dec in decorators:
                fun = dec(fun)
        return fun
    return deco

import functools
def my_decorator_01(msg=None):
    # 装饰器函数,参数 func 是被装饰的函数
    def decorator(func):
        print('第1个装饰器--传入的2222参数', func.__name__)
        @functools.wraps(func)
        def wrapper(*args, **kw):
            for key, data in kw.items():
                print('参数-> %s--值是:%s' % (key, data))

            # 函数的处理回调
            print('第1个装饰器--传入的参数', func.__name__)
            print('第1个装饰器--传入的参数',msg)
            print('第1个装饰器--start')
            funcv= func(*args, **kw)
            print('第1个装饰器--end')
            return funcv
        return wrapper
    return decorator


if __name__ == '__main__':
    app = create_app()
    @composed_decorator(my_decorator_01(msg="参数1"),app.route(quanxian='asas', des='描述', rule='/backend_health222', methods=['POST', 'GET']), is_reversed=False)
    def backend_health222():
        return 'ok'

    print(app.url_map)
    app.run(host='127.0.0.1', port='8808', debug=True, threaded=False)

个人其他博客地址

简书:https://www.jianshu.com/u/d6960089b087

掘金:https://juejin.cn/user/2963939079225608

小钟同学 | 文 【原创】| QQ:308711822

  • 1:本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。
  • 2:关于文章内容,有部分内容参考自互联网,如有链接会声明标注;如没有及时标注备注的链接的,如有侵权请联系,我会立即删除处理哟。


原文作者:程序员小钟同学;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2021-02-20

  • 博文量
    224
  • 访问量
    111711