標籤:最新 調用 class 傳回值 解決 添加 直接 highlight tar
裝飾器上下五千年和前世今生,這裡我們始終要問,裝飾器為何產生?裝飾器產生解決了什麼問題?什麼樣的需求推動了裝飾器的產生?思考問題的時候,始終要問,為什麼要這樣,而不是那樣或者其他樣。這裡我不先說,也不直接把裝飾器的最終樣子擺出來,而是說說裝飾器發展過程,從這些過程中知道,不是技術推動技術的發展,而是解決這個需求推動技術的產生。接下來一步步構建裝飾器產生的過程,從最原始的方向來到最新的狀態來解說裝飾器為何產生,裝飾器產生的過程是如何演變的。
下面是一段簡代碼,實現的功能是暫停1秒,然後再列印一句問好"Hai, 北門吹雪"
import timedef bei_men_chui_xue(): time.sleep(1) print("Hai, 北門吹雪")bei_men_chui_xue()
這裡需求來了,誰誰誰,總是在提需求,殺了祭天。
哎呀,在這個功能上在添加一個小小的功能,就是一個小小功能,輸出一下這個功能的已耗用時間,不難吧?
默默的掏出身後的板磚,啪的一下拍在桌子上,昨天晚上你不是這樣說的,說好不改需求的,今天早上就翻臉了?
好吧,我默默的去改需求了,提交了方案 1
import timedef bei_men_chui_xue(): time.sleep(1) print("Hai, 北門吹雪")start_time = time.time()bei_men_chui_xue()print("run time:", time.time() - start_time)
雖然實現了這個需求,但是這個直接內嵌程式碼邏輯,把功能代碼邏輯包圍了起來,看起來不夠優雅,改得好看點好嗎?
好吧,我又默默器去修改需求了,提交了方案2
import timedef bei_men_chui_xue(): time.sleep(1) print("Hai, 北門吹雪")def get_run_time(func): start_time = time.time() func() end_time = time.time() print(end_time - start_time)# 高階函數,已經很優雅的解決方案get_run_time(bei_men_chui_xue)
很好,使用了高階函數,居然知道Python中一切皆對象的原理,把擷取時間的功能封裝成一個函數,試試用閉包去實現?
好吧,我又默默器去修改需求了,提交了方案3
import timedef bei_men_chui_xue(): time.sleep(1) print("Hai, 北門吹雪")def get_run_time(func): def wrapper(): start_time = time.time() func() end_time = time.time() print(end_time - start_time) return wrapper# 閉包解決方案,看起來方案2遠比這個優雅f = get_run_time(bei_men_chui_xue)f()
嗯,非常好,我也覺得方案2好,但是你修改了源碼,改變了源碼的執行邏輯,嘗試不改變源碼邏輯?
好吧,我又默默器去修改需求了,提交了方案4
import timedef get_run_time(func): def wrapper(): start_time = time.time() func() end_time = time.time() print(end_time - start_time) return wrapper@get_run_timedef bei_men_chui_xue(): time.sleep(1) print("Hai, 北門吹雪")# 裝飾器解決方案,前面的文法糖才是裝飾器核心bei_men_chui_xue()
不錯不錯,裝飾器把被裝飾函數傳遞進裝飾器,調用源函數其實本質上調用裝飾器中的wrapper函數,我想在原函數傳遞進去參數,如何?
好吧,我又默默器去修改需求了,提交了方案5
import timedef get_run_time(func): def wrapper(*args, **kwargs): start_time = time.time() func(*args, **kwargs) end_time = time.time() print(end_time - start_time) return wrapper@get_run_timedef bei_men_chui_xue(name): time.sleep(1) print("Hai, %s" % name)# 解決裝飾的函數有變數bei_men_chui_xue("北門吹雪")
很好,很好,通過往裝飾器中傳遞 *args **kwargs參數完成向原函數傳遞參數,我想獲得一下原函數的傳回值?如被裝飾函數的傳回值?
好吧,我又默默器去修改需求了,提交了方案6
import timedef get_run_time(func): def wrapper(*args, **kwargs): start_time = time.time() r = func(*args, **kwargs) end_time = time.time() run_time = end_time - start_time print(run_time) # 被裝飾函數傳回值 return r return wrapper@get_run_timedef bei_men_chui_xue(name): time.sleep(1) return "Hai, %s" % name# 解決裝飾的函數有變數r = bei_men_chui_xue("北門吹雪")print(r)
功能還需要改動,我不想輸出其已耗用時間,可以通過向裝飾器中傳入參數,如果已耗用時間超過這個數列印已經逾時?
好吧,我又默默器去修改需求了,提交了方案7
import timedef get_run_time(time_out): def out_wrapper(func): def wrapper(*args, **kwargs): start_time = time.time() r = func(*args, **kwargs) end_time = time.time() # 擷取已耗用時間 run_time = end_time - start_time # 檢查程式已耗用時間是否逾時 if run_time > time_out: print("已耗用時間已經逾時") # 被裝飾函數傳回值 return r return wrapper return out_wrapper@get_run_time(time_out=1)def bei_men_chui_xue(name): time.sleep(1) return "Hai, %s" % namebei_men_chui_xue("北門吹雪")# 擷取傳回值r = bei_men_chui_xue("北門吹雪")print(r)
完美,這個才是五彩斑斕的黑,加個雞腿
從這個過程中可以看出,被裝飾函數運行時候其實啟動並執行是裝飾器內部wrapper函數,通過函數閉包實現對一些參數狀態的儲存,從而實現各種需求的裝飾器
Python-裝飾器上下五千年和前世今生