裝飾器_二(自定義裝飾器)

什麼是裝飾器:

裝飾器利用了函數也可以作爲參數傳遞和閉包的特性,可以讓我們的函數在執行之前或者執行之後方便的添加一些代碼。這樣就可以做很多的事情了,比如@classmethod裝飾器可以將一個普通的方法置爲類方法,@staticmethod裝飾器可以將一個普通的方法置爲靜態方法等。所以明白了裝飾器的原理後,我們就可以自定義裝飾器,從而實現我們自己的需求。
理解:
拿網站開發的例子來說。網站開發中,經常會碰到一些頁面是需要登陸後才能訪問的。那麼如果每次都在訪問視圖函數中判斷,很麻煩,而且代碼很難維護。

user = {
    'is_login': False
}

def edit_user():
    if user['is_login'] == True:
        print('用戶名修改成功')
    else:
        print('跳轉到用戶登陸界面')

def add_article():
    if user['is_login'] == True:
        print('文章添加成功')
    else:
        print('跳轉到用戶登陸界面')
        
edit_user()
add_article()

以上現在只是兩個函數,如果網站越來越大,需要判斷的地方也越來越大,那麼這種判斷將顯得非常低效並且難於維護。
使用裝飾器來實現判斷網站登陸:

def check_login(func):
    # wrapper這個函數名字可以自定義,一般習慣性用這個名字
    def wrapper():
        if user['is_login'] == True:
            func()
        else:
            print('跳轉到用戶登陸界面')
    return wrapper


@check_login
def edit_user():
    print('用戶名修改成功')


def add_article():
    if user['is_login'] == True:
        print('文章添加成功')
    else:
        print('跳轉到用戶登陸界面')

# 執行 edit_user() == check_login(edit_user)()
# edit_user = wrapper
edit_user()

被裝飾器的函數帶有參數

上述我們實現的對登陸的裝飾,如果登陸是需要傳遞用戶名,來指出是誰登陸成功了,在添加文章的時候需要傳遞文章的標題和內容,這時我們就需要傳遞參數

# -*- coding: UTF-8 -*-

user = {
    'is_login': True
}

def check_login(func):
    # wrapper這個函數名字可以自定義,一般習慣性用這個名字
    def wrapper(*args, **kwargs):
        print(kwargs)
        if user['is_login'] == True:
            func(*args, **kwargs)
        else:
            print('跳轉到用戶登陸界面')
    return wrapper


@check_login
def edit_user(username):
    print('用戶名%s 修改成功' % username)

@check_login
def add_article(title=None, content=None):
    print('%s %s 添加成功' % (title, content))


# 執行 edit_user() == check_login(edit_user)()
# edit_user = wrapper
edit_user('lyc')
add_article(title='測試', content='文章內容')

給裝飾器傳遞參數

應用場景:當我們需要區分是前臺還是後臺調用修改用戶的接口,來區分返回跳轉到前臺登陸頁面還是後臺登陸頁面時

user = {'is_login': True}

def login_required(site='front'):
    def outer_wrapper(func):
        def inner_wrapper(*args, **kwargs):
            if user['is_login'] == True:
                func(*args, **kwargs)
            else:
                if site == 'front':
                    print('跳轉到前臺登陸頁面')
                else:
                    print('跳轉到後臺登陸頁面')
        return inner_wrapper
    return outer_wrapper

@login_required('front')
def edit_user(username):
    print('用戶名%s 修改成功' % username)

edit_user('lyc')

wraps裝飾器

from functools import wraps

def greet(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print('%s start run' % func.__name__)
        func(*args, **kwargs)
        print('%s run end' % func.__name__)
    return wrapper

@greet
def add(x, y):
    print('%d + %d = %d' %(x, y, x+y))

add(1, 19)
print(add.__name__)

如果我們不用wraps裝飾器,那麼print(add.name) 打印結果爲 wrapper。 因此,我們在自定義裝飾器的時候,要注意在實際執行函數前加上wraps裝飾器,避免這種情況發生。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章