裝飾器:本質(zhì)就是函數(shù),功能是為其他函數(shù)添加附加功能
原則:
裝飾器 = 高階函數(shù) + 函數(shù)嵌套 + 閉包
高階函數(shù)定義:
test 函數(shù)是高階函數(shù),接受了一個foo 作為參數(shù)
import time def foo(): time.sleep(3) print("sleep 3s") def test(func): start_time = time.time() func() stop_time = time.time() print("函數(shù)的運行時間是: %s" % (stop_time - start_time)) test(foo)
timer 是一個高階函數(shù),這個函數(shù)返回值是一個函數(shù)
import time def foo(): time.sleep(3) print("sleep 3s") def timer(func): start_time = time.time() func() stop_time = time.time() print("執(zhí)行時間{}".format(stop_time - start_time)) return func foo = timer(foo) foo() # 結(jié)果: 多運行了一次
在函數(shù)里面定義函數(shù),變量的作用域和生存周期不變。
def father(name): print("father name: %s" % name) def son(): print("son name: %s" % name) son() father("xu1") # 結(jié)果: # father name: xu1 # son name: xu1
實現(xiàn)一個計算函數(shù)執(zhí)行時間的函數(shù)作為裝飾器,用來計算被裝飾函數(shù)的執(zhí)行時間并打印
import time def timer(func): # 實現(xiàn)一個計算函數(shù)執(zhí)行時間的函數(shù)作為裝飾器,用來計算被裝飾函數(shù)的執(zhí)行時間并打出 def wrapper(): start_time = time.time() func() stop_time = time.time() print("運行時間: %s" % (stop_time - start_time)) return wrapper # def test(): # 不使用裝飾器的同等實現(xiàn) # time.sleep(3) # print("test sleep 3s") # # test = timer(test) # 返回的是 wrapper 的地址 # test() # 執(zhí)行的是 wrapper @timer def test(): # 裝飾器的實現(xiàn) time.sleep(3) print("test sleep 3s") test() # 執(zhí)行的是 wrapper # 結(jié)果: # test sleep 3s # 運行時間: 3.000915050506592
import time def timer(func): def wrapper(): start_time = time.time() res = func() # 執(zhí)行被裝飾方法 stop_time = time.time() print("運行時間: %s" % (stop_time - start_time)) return res # 接受正在調(diào)用的方法的返回值,并返回 return wrapper @timer def test(): time.sleep(3) print("test sleep 3s") return "test return ok" print(test()) # 執(zhí)行的是 wrapper # 結(jié)果: # test sleep 3s # 運行時間: 3.0002923011779785 # test return ok
import time def timer(func): """ *args:將被修飾方法傳入的非關(guān)鍵字參數(shù)打包為元組 args **kwargs: 將被修飾方法傳入的關(guān)鍵字參數(shù)打包為字典 kwargs """ def wrapper(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) # *args 拆解元組,按順序傳給被修飾函數(shù); **kwargs:拆解字典 stop_time = time.time() print("運行時間: %s" % (stop_time - start_time)) return res return wrapper @timer # 給test 方法添加計算執(zhí)行時間的裝飾器 def test(name, age): time.sleep(3) print("name = {}, age = {}".format(name, age)) return "test return ok" # 調(diào)用被裝飾器裝飾的方法 print(test("xu", 100)) # 執(zhí)行的是 wrapper # 結(jié)果: # name = xu, age = 100 # 運行時間: 3.000420331954956 # test return ok
假如 index() 、home()、shopping_car() 三個方法都需要登錄后才能訪問(無法訪問時里面不輸入對應(yīng)內(nèi)容),正常情況下只需登錄一次,后面訪問其他方法就無需再次登錄。
可以通過@auth_fun裝飾器進行驗證用戶是否登錄,如果沒有就讓用戶輸入賬號密碼,用戶賬號密碼正確的記錄當(dāng)前登錄的用戶,其他方法無需再次登錄。
# 用戶列表 user_list = [ {'name': 'xu1', 'passwd': '123'}, {'name': 'xu2', 'passwd': '123'}, {'name': 'xu3', 'passwd': '123'}, {'name': 'xu4', 'passwd': '123'}, ] # 當(dāng)前登錄的用戶 current_dic = {"username": None, "login": False} # 驗證用戶是否登錄的裝飾器 # 如果用戶沒有登錄,讓用戶輸入賬號密碼,校驗通過記錄用戶狀態(tài) def auth_fun(func): def wrapper(*args, **kwargs): if current_dic["username"] and current_dic['login']: res = func(*args, **kwargs) return res username = input("請輸入用戶名:") pw = input("請輸入密碼:") for u in user_list: if u["name"] == username and u["passwd"] == pw: current_dic["username"] = username current_dic["login"] = True res = func(*args, **kwargs) return res else: print("用戶沒有注冊!") return wrapper @auth_fun def index(): print("this is index") @auth_fun def home(): print("this is home page") @auth_fun def shopping_car(): print("this is shopping car") index() # 輸入用戶密碼 home() # index 已經(jīng)登錄,無需在輸入 shopping_car() # index 已經(jīng)登錄,無需在輸入 # 結(jié)果: # 請輸入用戶名:xu1 # 請輸入密碼:123 # this is index # this is home page # this is shopping car
裝飾器帶參數(shù),最簡單的操作就是可以對被裝飾的函數(shù)進行區(qū)別處理。
# 用戶列表 user_list = [ {'name': 'xu1', 'passwd': '123'}, {'name': 'xu2', 'passwd': '123'}, {'name': 'xu3', 'passwd': '123'}, {'name': 'xu4', 'passwd': '123'}, ] # 當(dāng)前登錄的用戶 current_dic = {"username": None, "login": False} """ 注意:帶參數(shù)的裝飾器會比沒有帶參數(shù)的裝飾器多嵌套一層函數(shù)(多了auth) 調(diào)用方式是 @auth(auth_type="type1"), 返回 auth_fun, 也就是說 @auth(auth_type="type1")相當(dāng)于 @auth_fun 但是 auth_fun 函數(shù)所在的嵌套作用域多了一個 auth_type 的變量 """ def auth(auth_type="type1"): def auth_fun(func): def wrapper(*args, **kwargs): if auth_type == "type1": if current_dic["username"] and current_dic['login']: res = func(*args, **kwargs) return res username = input("請輸入用戶名:") pw = input("請輸入密碼:") for u in user_list: if u["name"] == username and u["passwd"] == pw: current_dic["username"] = username current_dic["login"] = True res = func(*args, **kwargs) return res else: print("用戶沒有注冊!") elif auth_type == "type2": print("不用授權(quán)直接登錄: type = {}".format(auth_type)) res = func(*args, **kwargs) return res else: print("其他type沒有實現(xiàn)") return wrapper return auth_fun """ auth_fun = @auth(auth_type="type1") auth_fun 所在的嵌套與將有一個 auth_type 變量 然后通過 @auth()方法返回的對象注解 index,相當(dāng)于 @auth_fun 注解index 方法,最后得到 wrapper 對象 """ @auth(auth_type="type1") def index(): print("this is index") @auth(auth_type="type2") def home(): print("this is home page") @auth(auth_type="type3") def shopping_car(): print("this is shopping car") home() # 注意:auth_type="type2",這個方法無需登錄可以直接執(zhí)行 index() # 注意:auth_type="type1",需要登錄 shopping_car() # 注意:auth_type="type3",沒有做處理 # 結(jié)果: # 不用授權(quán)直接登錄: type = type2 # this is home page # 請輸入用戶名:xu1 # 請輸入密碼:123 # this is index # 其他type沒有實現(xiàn)
到此這篇關(guān)于python基礎(chǔ)之裝飾器詳解的文章就介紹到這了,更多相關(guān)python裝飾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!