python裝飾器
網上面有很多優秀的文章寫得很好,但是每個人的思路和接受的方式都不一樣,我選用了自己能看得懂再加上自己的理解寫了這篇博客,將分為多步實現對裝飾器的理解,作為新手入門級別,另外會在結束後,給上我認為優秀文章的鏈接。。。。幫助有緣人徹底起飛
裝飾器是一個很著名的設計模式,經常被用於有切面需求的場景,較為經典的有插入日誌、性能測試、事務處理等。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量函數中與函數功能本身無關的雷同代碼並繼續重用。概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能。
原則:1.不能修改被裝飾函數的源代碼
2.不能修改被裝飾函數的調用方法
廢話不多說,開整吧!
第一步:準備給一個函數添加一個新的功能
def foo(): time.sleep(3) print(‘in the foo‘) foo()
我首先想到會這樣做
def foo(): start_time = time.time() time.sleep(3) print(‘in the foo‘) end_time = time.time() print(‘code run time is %s‘%(end_time-start_time)) foo()
直接修改源碼,違背原則1,顯然任務量很大,而且很low
於是乎,我想到了似low非low
def timer(): start_time = time.time() foo() end_time = time.time() print(‘code run time is %s‘ % (end_time - start_time)) timer()
或者
def timer(func): start_time = time.time() func() end_time = time.time() print(‘code run time is %s‘ % (end_time - start_time)) timer(foo) 直接寫一個計算運行時間的函數,把需要添加功能的函數放進來,這樣就可以不改變源碼了,但是調用方法卻從foo()---->timer()和timer(foo),違背原則2,假設foo()在多處被修改,
那麽我們是不是也要去把所有的foo()換成timer(foo)呢?
但是不要著急,因為我們已經實現了不改變源碼那一步,現在只需要將調用方法timer(foo)變成-----》foo()即可,我們何不把timer賦值給foo,等等,timer似乎帶有一個參數.......
顯然你不可能把timer(foo)賦值給foo,然後再調用foo(),這個為什麽不能的原因如果不知道就扇自己一個大嘴巴子吧........什麽?扇完還不知道!timer(foo)是函數調用的結果,結果
能當函數調用嗎.....我們要想timer(foo)不是直接產生調用結果,那就必須讓他返回一個與foo參數一致的函數,然後就可以把timer(foo)賦值給foo,再調用foo()
怎麽才能做到這一點呢?必須要用到嵌套函數,在timer函數體裏再def定義一個函數,然後返回這個函數
def timer(func): def deco(): start_time = time.time() func() end_time = time.time() print(‘code run time is %s‘ % (end_time - start_time)) return deco foo=timer(foo) foo()
可以說,基本上已經完成了一個裝飾器,粘貼一段話以示尊敬
在這個例子中,函數進入和退出時需要計時,這被稱為一個橫切面(Aspect),這種編程方式被稱為面向切面的編程(Aspect-Oriented Programming)。與傳統編程習慣的從上往下執行方式相比較而言,像是在函數執行的流程中橫向地插入了一段邏輯。在特定的業務領域裏,能減少大量重復代碼。面向切面編程還有相當多的術語,這裏就不多做介紹,感興趣的話可以去找找相關的資料。
你以為就這樣結束了???so young
現在foo()裏有參數了
def timer(func): def deco(a,b): start_time = time.time() ret = func(a,b) end_time = time.time() print(‘code run time is %s‘ % (end_time - start_time)) return ret return deco @timer def foo(a,b): time.sleep(3) print(‘in the foo‘) return a+b foo(1,2)
[email protected],這個叫做語法糖,有了這個就可以省去foo= timer(func)
現在不確定往foo()傳什麽參數,還好python裏面有*args和**kwargs,可變參數
def timer(func): def deco(*args,**kwargs): start_time = time.time() ret = func(*args,**kwargs) end_time = time.time() print(‘code run time is %s‘ % (end_time - start_time)) return ret return deco @timer def foo(a,b): time.sleep(3) print(‘in the foo‘) return a + b @timer def foo2(a,b,c): time.sleep(3) print(‘in the foo‘) return a + b +c foo(1,2) foo2(1,2,3)
還可以讓裝飾器帶參數,今晚就先到這裏了,明天還要上班,待更新
python裝飾器