python之裝飾器詳解
一、裝飾器定義
定義一個函數,可以接受一個函數作為參數,對該函數進行一些包裝,不改變函數的本身。
二、裝飾器四部曲(分解)
1、函數可賦值給變量。若賦值給變量的是調用后的函數,變量的值就是return的返回值。
切記:函數賦值給變量,只看return的值。分清楚函數是處于調用狀態還是未被調用狀態。若函數沒有寫return,默認return為None。
例如:
解釋:把函數foo賦值給a和b,a賦值的是調用后的函數,變量的值就是返回值。b賦值的是調用前的函數,所以b就是那個賦值的函數。函數本身+(),就是調用。
可以用callable判斷某個東西是否可以被調用,call是調用的意思,able是“能的”形容詞后綴,翻譯就是可調用的。b是函數本身,可以被調用,a是函數的結果,不能被調用。
小技巧:
我們可以用.name看一個函數的信息,例如:b函數其實就是‘foo’函數。
2、函數可以作為參數傳遞,在函數內部仍可進行調用??梢詫⒑瘮翟趦炔慷x理解為一個變量在內部定義。
解釋:我先定義一個函數foo,然后再定義一個函數bar,我調用foo的時候,即foo(),沒有設置傳遞參數,打印了1234.我調用bar的時候,傳遞了一個函數foo作為參數,即bar(foo),得到的結果就是func(),調用函數本身,所以得到1234的結果。
3、函數可嵌套定義,并可在內部直接調用。且可調用外層函數傳遞的參數。這一步很關鍵。
解釋:內層函數可以調用外層函數傳遞的參數,f(1234)傳遞給了內層函數。內層沒有找到x變量的值,就要去臨近的外層變量尋找。外層傳遞一個1234,就傳遞給內層了。最后一行的bar()是在外層函數的內部直接調用內層函數。
函數嵌套定義就是可以把函數看成定義一個變量,類似于b=1,還有就是內層函數可以調用外層函數傳遞的參數,記住這兩點就可以了。
4、函數可以作為return的返回值
解釋:上面定義了一個函數,下面定義了一個函數返回函數。對變量a進行賦值,可以使用a.__name__看到a的函數名,a就是bar,為什么是bar呢,因為第一條:給變量a賦值的時候,只看return,return的是函數的函數func,所以是bar。
三、組合起來就是裝飾器
解釋:最后的foo就是wrapper,就是deco(foo),是內層函數“g()”,可以用foo.name查看,就是wrapper,callable(foo),可以看到它可以調用。
還有一點,如下圖,筆者在學習過程中碰到的一點疑問:
上面的三個過程,第一個是給變量賦值的過程,第二個是打印變量的過程,第三個是函數調用的過程。變量賦值看return,不要看他出現什么結果,這個時候就是把return的1賦值給a,所以打印a才會出來1,函數調用的過程,就是執行函數內部程序的過程,函數內部有一個打印,一個return,所以才會出現這樣的結果。
這樣,我們就很好理解上面的結果了。
上面的這個“函數賦值給變量”就是裝飾器的核心原理,裝飾器接受函數作為參數完成調用,再將返回結果賦值給該函數同名的變量。以后再通過該變量名調用,就是被裝飾器裝飾過的函數。
四、python裝飾器用法:@
解釋:@deco相當于foo=deco(foo)。
1、內層函數也可以定義參數:
解釋:參數的傳遞是先傳給wrapper,wrapper在把這個參數傳遞給func進行調用。wrapper接受的參數的個數要跟foo的一樣,我要通過wrapper轉給foo。
2、裝飾器方法總結:
通常最內層函數的倒數第二層函數,定義接受一個函數參數
裝飾器內部嵌套定義了什么函數,就要講該函數作為return返回值,未調用的。
最內層函數的參數定義最好和傳人的參數定義一致,或者使用(*arg,*kwargs)這種可變參數的定義方式。
裝飾器外層函數只會執行一次。外層的操作執行完成后,就不會再輸出了。執行的都是內層函數wrapper。
對裝飾的函數進行屬性傳遞:被裝飾的函數的name,名稱,doc注釋等等,都無法保留,都是內層函數的,這個時候就要把wrapper的屬性改掉,改成我們接受函數的屬性。也有一個專門的模塊:from functools import wraps。用法@wraps(func)
nonlocal:python可以使用外部函數變量,無法修改外部函數自身。此時可以用nonlocal關鍵字標記需要修改的變量就可以修改該變量的值了。例如統計函數的次數:
帶參數的裝飾器:無非就是再加一層,內部可以不用動。如下,增加一個參數123.
原創文章,作者:N24_yezi,如若轉載,請注明出處:http://www.www58058.com/67878
原理分解的很詳細,步驟完善。