概念:
1.裝飾器的實現是由閉包支撐的;
2.裝飾器本質上是⼀個python函數,它可以在讓其他函數在不需要做任何代碼的變動的前提下增加額外的功能;
3.裝飾器的返回值也是⼀個函數的對象,它經常用於有切面需求的場景,實現路由傳參,flask的路由傳參依賴於裝飾器,瀏覽器通過url訪問到裝飾器的路由,從而訪問視圖函數獲得返回的HTML頁面;
應用場景:
1.可以在外層函數加上時間計算函數,計算函數運行時間;
2.計算函數運行次數;
3.可以用在框架的路由傳參上;
4.插入日誌,作爲函數的運行日誌;
5.事務處理,可以讓函數實現事務的一致性,讓函數要麼一起運行成功,要麼一起運行失敗;
6.緩存,實現緩存處理;
7.權限的校驗,在函數外層套上權限校驗的代碼,實現權限校驗;
寫出一個單例的裝飾器(使一個本來不是單例類的類變成單例類))
- def set_func(func):
- __singleton = None
- def call_func(*args, **kwargs):
- nonlocal __singleton
- if not __singleton:
- __singleton = func(*args, **kwargs)
- return __singleton
- else:
- return __singleton
- return call_func
- @set_func
- class Std(object):
- def __init__(self, name, age):
- self.name = name
- self.age = age
- s2 = Std('jack',18)
- print(id(s2),s2.name,s2.age)
- s1 = Std('leo',23)
- print(id(s1),s1.name,s1.age)
運行結果:
- 139727292442832 jack 18
- 139727292442832 jack 18
上下文提供者(Context Provider)
上下文裝飾器被用來確保函數在正確的上下文環境運行,或者確保在函數運行前和運行後執行一些代碼。換言之,該裝飾器進行設置或取消設置某個特定的運行環境。例如,當一條數據要在多個線程之間共享時,就需要使用鎖(lock)來確保數據被保護,以防出現併發訪問。鎖能夠像下面這樣放在裝飾器
上下文裝飾器,通常被上下文管理器(with 語句)取代。from threading import RLock
lock = RLock()
def synchronized(function):
def _synchronized(*args, **kw):
lock.acquire()
try:
return function(*args, **kw)
finally:
lock.release()
return _synchronized
@synchronized
def thread_safe(): # make sure it locks the resource
pass
登錄判斷裝飾器:
之前做過的一個用flask框架實現的移動app項目,裏面大量用到是否已經登錄的判斷,如果這個業務邏輯大量重複地寫在視圖函數,代碼的複用性很差,因此我將登錄判斷封裝成裝飾器,然後用這個裝飾器裝飾每一個需要驗證是否登錄的視圖函數,代碼如下:
- def login_required(view_func):
- """自定義裝飾器判斷用戶是否登錄"""
- @wraps(view_func)
- def wrapper(*args, **kwargs):
- """具體實現判斷用戶是否登錄的邏輯"""
- user_id = session.get('user_id')
- if not user_id:
- return jsonify(errno=RET.SESSIONERR, errmsg='用戶未登錄')
- else:
- g.user_id = user_id
- return view_func(*args, **kwargs)
- return wrapper