1. 程式人生 > >Python多個Decorator裝飾器的使用

Python多個Decorator裝飾器的使用

在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)