python基礎(chǔ)之裝飾器詳解
一、前言
裝飾器:本質(zhì)就是函數(shù),功能是為其他函數(shù)添加附加功能
原則:
- 1、不修改被修飾函數(shù)的源代碼
- 2、不修改被修飾函數(shù)的調(diào)用方式
裝飾器 = 高階函數(shù) + 函數(shù)嵌套 + 閉包
二、高階函數(shù)
高階函數(shù)定義:
- 1、函數(shù)接收的參數(shù)是一個函數(shù)
- 2、函數(shù)的返回值是一個函數(shù)名
- 3、滿足上述條件任意一個,都可以稱為高階函數(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ù)的運(yùn)行時間是: %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é)果: 多運(yùn)行了一次
三、函數(shù)嵌套
在函數(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("運(yùn)行時間: %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 # 運(yùn)行時間: 3.000915050506592
4.1 被裝飾方法帶返回值
import time def timer(func): def wrapper(): start_time = time.time() res = func() # 執(zhí)行被裝飾方法 stop_time = time.time() print("運(yùn)行時間: %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 # 運(yùn)行時間: 3.0002923011779785 # test return ok
4.2 被裝飾方法帶參數(shù)
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("運(yùn)行時間: %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 # 運(yùn)行時間: 3.000420331954956 # test return ok
4.3 驗證功能裝飾器
假如 index() 、home()、shopping_car() 三個方法都需要登錄后才能訪問(無法訪問時里面不輸入對應(yīng)內(nèi)容),正常情況下只需登錄一次,后面訪問其他方法就無需再次登錄。
可以通過@auth_fun裝飾器進(jìn)行驗證用戶是否登錄,如果沒有就讓用戶輸入賬號密碼,用戶賬號密碼正確的記錄當(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
4.4 驗證功能裝飾器——帶參數(shù)
裝飾器帶參數(shù),最簡單的操作就是可以對被裝飾的函數(shù)進(jìn)行區(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)文章希望大家以后多多支持腳本之家!
相關(guān)文章
卸載所有通過pip安裝的Python包的方法總結(jié)(Windows系統(tǒng))
這篇文章主要介紹了卸載所有通過pip安裝的Python包的方法總結(jié)(Windows系統(tǒng)),文中通過代碼示例和圖文講解的非常詳細(xì),并具有一定的參考價值,需要的朋友可以參考下2024-08-08簡要講解Python編程中線程的創(chuàng)建與鎖的使用
這篇文章主要介紹了簡要講解Python編程中線程的創(chuàng)建與鎖的使用,Python中雖然有GIL的存在,但依然是能夠創(chuàng)建多個線程來交替使用的,需要的朋友可以參考下2016-02-02Python基礎(chǔ)之循環(huán)語句用法示例【for、while循環(huán)】
這篇文章主要介紹了Python基礎(chǔ)之循環(huán)語句用法,結(jié)合實例形式分析了Python使用for、while循環(huán)及range、break和continue語句相關(guān)使用技巧,需要的朋友可以參考下2019-03-03python 處理telnet返回的More,以及get想要的那個參數(shù)方法
今天小編就為大家分享一篇python 處理telnet返回的More,以及get想要的那個參數(shù)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-02-02python數(shù)據(jù)分析基礎(chǔ)知識之shape()函數(shù)的使用教程
shape函數(shù)是numpy.core.fromnumeric中的函數(shù),它的功能是讀取矩陣的長度,比如shape[0]就是讀取矩陣第一維度的長度,下面這篇文章主要給大家介紹了關(guān)于python數(shù)據(jù)分析基礎(chǔ)知識之shape()函數(shù)使用的相關(guān)資料,需要的朋友可以參考下2022-09-09python 實現(xiàn)將字典dict、列表list中的中文正常顯示方法
今天小編就為大家分享一篇python 實現(xiàn)將字典dict、列表list中的中文正常顯示方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07