python裝飾器詳解

python之裝飾器詳解

一、裝飾器定義

定義一個函數,可以接受一個函數作為參數,對該函數進行一些包裝,不改變函數的本身。

二、裝飾器四部曲(分解)

1、函數可賦值給變量。若賦值給變量的是調用后的函數,變量的值就是return的返回值。

切記:函數賦值給變量,只看return的值。分清楚函數是處于調用狀態還是未被調用狀態。若函數沒有寫return,默認return為None。

例如:

解釋:把函數foo賦值給a和b,a賦值的是調用后的函數,變量的值就是返回值。b賦值的是調用前的函數,所以b就是那個賦值的函數。函數本身+(),就是調用。

可以用callable判斷某個東西是否可以被調用,call是調用的意思,able是“能的”形容詞后綴,翻譯就是可調用的。b是函數本身,可以被調用,a是函數的結果,不能被調用。

小技巧:

我們可以用.name看一個函數的信息,例如:b函數其實就是‘foo’函數。

2、函數可以作為參數傳遞,在函數內部仍可進行調用。可以將函數在內部定義理解為一個變量在內部定義。

解釋:我先定義一個函數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.

相關新聞

聯系我們

400-080-6560

在線咨詢:點擊這里給我發消息

郵件:[email protected]

工作時間:周一至周日,09:00-18:30

QR code
云南快乐10分开奖直播