什麼是裝飾器:
裝飾器利用了函數也可以作爲參數傳遞和閉包的特性,可以讓我們的函數在執行之前或者執行之後方便的添加一些代碼。這樣就可以做很多的事情了,比如@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裝飾器,避免這種情況發生。