情景介紹
一天,在你正在努力加班的時候,老板給交給你了一個任務,就是在這段代碼里將所有函數開始輸出一個‘hello’最后輸出當前時間,再輸出一個“end”,這段代碼里包含了大量的函數,你會怎么做?
def f1(): print('proces a') def f2(): print('proces b') def f3(): print('proces c') def f4(): print('proces d') ... ...
剛拿到這個任務,我們可能想着這樣做,在每個函數中添加相應的輸出語句,這樣就能完成任務。
import datetime def f1(): print('hello') print('proces a') print('datetime.datetime.now()') print('end') def f2(): print('hello') print('proces b') print('datetime.datetime.now()') print('end') def f3(): print('hello') print('proces c') print('datetime.datetime.now()') print('end') def f4(): print('hello') print('proces d') print('datetime.datetime.now()') print('end') ... ...
到我們進行實施的時候我們發現這樣寫,太麻煩,每一個函數最后都要添加一遍,於是,我們就想到了另一個方法,就是寫一個函數,添加在每個函數中。
import datetime def hel(): print('hello') print(datetime.datetime.now()) print('end') def f1(): print('hello') print('proces a') hel() def f2(): print('hello') print('proces b') hel() def f3(): print('hello') print('proces c') hel() def f4(): print('hello') print('proces d') hel() ... ...
但是我們發現在開始輸出的hello還是要添加在每個函數中,這樣還是麻煩,為了解決這個問題就要講講裝飾器了。
裝飾器介紹
裝飾器本質上是一個Python函數,它可以讓其他函數在不需要做任何代碼變動的前提下增加額外功能,裝飾器的返回值也是一個函數對象。它經常用於有切面需求的場景,比如:插入日志、性能測試、事務處理、緩存、權限校驗等場景。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量與函數功能本身無關的雷同代碼並繼續重用。概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能。
簡單裝飾器
就將開始那個問題來使用裝飾器解決一下。
import datetime def hel(func): def inner(): print('hello') r = func() print(datetime.datetime.now()) print('end') return r return inner @hel def f1(): print('proces a') @hel def f2(): print('proces b') @hel def f3(): print('proces c') @hel def f4(): print('proces d') f1() f2() f3() f4() 執行結果: hello proces a 2018-06-24 18:03:21.903651 end hello proces b 2018-06-24 18:03:21.915651 end hello proces c 2018-06-24 18:03:21.915651 end hello proces d 2018-06-24 18:03:21.915651 end
是不是使用裝飾器相對於之前的寫法簡單。
針對上面的代碼進行解析:
裝飾器符號“@”屬於語法糖,@修飾符必須出現在函數定義前一行,將下面的函數的名作為參數,不允許和函數定義在同一行。
在上面的代碼中,func就是指f1、f2、f3、f4函數,以f1為例,將f1函數作為參數傳入hel函數中,在hel函數中再定義一個inner()函數,在inner函數中,首先執行一個print('hello'),在執行f1函數兵將返回值賦值給r,接下來輸出時間以及end,最后返回r,inner函數的最后返回inner函數,當我們執行f1函數的時候,就相當於執行了inner函數,並且可以可以拿到f1函數的返回值。
使用裝飾器傳遞參數
上面使用的裝飾器中,傳入的函數沒有帶參數,當需要修飾的函數帶有參數,我們就在裝飾器中的inner函數添加相應的參數,在inner函數里面調用func函數的時候,再次傳入。
def hel(func): def inner(name): r = func(name) print('bye') return r return inner @hel def f1(name): print('hello') print(name) name = 'alexsel' f1(name) 輸出結果: hello alexsel bye
雖然這樣我們就解決了參數的問題,但是我們這次傳入的參數僅僅是字符串,如果是更加復雜的參數怎么辦,這時候我們可以使用我們之前學習函數時候用到的一些可以接收多種類型的參數,*args,**kwargs,使用這兩個參數之后我們可以接收任何類型的參數。
def hel(func): def inner(*args,**kwargs): r = func(*args,**kwargs) print('bye') return r return inner @hel def f1(name): print('hello') print(name) name = 'alexsel' f1(name) 輸出結果: hello alexsel bye
到這里,簡單的裝飾器就講完了,裝飾器還有更高級的用法,下一篇,裝飾器二會繼續給大家講解裝飾器。