美文网首页
多个Decorator装饰器的使用

多个Decorator装饰器的使用

作者: 蒋狗 | 来源:发表于2017-02-03 23:23 被阅读0次

在tornado项目中一些RequestHandler中的get(),post()方法需要验证登陆用户和用户权限,并返回template或者json。

class IndexHandler(RequestHandler):
    @render_json
    @login_required
    @permission_required(10001)
    get(self):
        pass

对于同一个get()方法使用了多个装饰器,运行的顺序一般是自上而下,但太多个装饰器个人认为还是比较难以理解。


Demo

def first_decorator(func):
    print('--first--')

    def first_wrapper(*args, **kwargs):
        print('------first---%s---' % func.__name__)
        return func(*args, **kwargs)
    return first_wrapper


def second_decorator(func):
    print('--second--')

    def second_wrapper(*args, **kwargs):
        print('------second---%s---' % func.__name__)
        return func(*args, **kwargs)
    return second_wrapper

@first_decorator
@second_decorator
def test_func_1():
    print('excute %s' % inspect.stack()[0][3])

定义了两个装饰器,并装饰了函数test_func_1(),此时应该输出:

--second--
--first--
------first---second_wrapper---
------second---test_func_1---
excute test_func_1

拆分装饰器@语法糖以后,等价于。

def test_func_1():
    print('excute %s' % inspect.stack()[0][3])

first_decorator(second_decorator(test_func_1))()

进一步拆分。

second_wrapper = second_decorator(test_func_1)  # 返回实际是second_wrapper
# second()
first = first_decorator(second_wrapper)  # second_wrapper 传入first_decorator()
first()

实际上首先执行了second_decorator(test_func_1)返回second_wrapper函数,而此时--second--已经打印了。

然后first_decorator()接受之前返回的second_wrapper并返回了first_wrapper函数,而此时--first--已经打印了。

最后执行first_wrapper(second_wrapper)(),先打印出------first---second_wrapper---了,因为此时first_decorator中接受的funcsecond_wrapper,然后执行func(*args, **kwargs)second_wrapper(),打印出------second---test_func_1---,最后执行test_func_1(),打印excute test_func_1
(感觉仍有问题,需要重新整理一下思路。)


模拟Handler

def login_required(func):
    def wrapper(self, *args, **kwargs):
        if not self.current_user:
            # 未登录情况
            raise Exception('please login')
        else:
            return func(self, *args, **kwargs)
    return wrapper


def permission_required(permission_code):
    def decorator(func):
        def wrapper(self, *args, **kwargs):
            if not self.current_user.permission_code == permission_code:
                raise Exception('not have permission')
            else:
                return func(self, *args, **kwargs)
        return wrapper
    return decorator


class User():
    def __init__(self, name, permission_code=0):
        self.name = name
        self.permission_code = permission_code


class BaseHandler():

    def __init__(self, current_user=None):
        self.current_user = current_user

    @login_required
    @permission_required(1)
    def get(self):
        print('get success')
        return 'hello'

    @permission_required(1)
    @login_required
    def post(self):
        print('post success')
        return 'hello'

是否能简化成一个装饰器?

# 简化成一个装饰器?
def check_login_permission(permission_code=0):
    # 0默认不需要权限
    def decorator(func):
        def wrapper(self, *args, **kwargs):
            if not self.current_user:
                raise Exception('please login')
            if permission_code and self.current_user.permission_code != permission_code:
                raise Exception('not have permission')
            return func(self, *args, **kwargs)
        return wrapper
    return decorator


class NewBaseHandler():

    def __init__(self, current_user=None):
        self.current_user = current_user

    @check_login_permission(0)
    def get(self):
        print('get success')
        return 'hello'

try:
    # user_1 = User('JiangW_1', 1)
    # new_base_handler = NewBaseHandler(user_1)
    new_base_handler = NewBaseHandler(None)
    new_base_handler.get()
except Exception as e:
    print(e)

相关文章

网友评论

      本文标题:多个Decorator装饰器的使用

      本文链接:https://www.haomeiwen.com/subject/pcqjittx.html