天天看點

python3 裝飾器

以上代碼看起來有些複雜,但它仍是易于了解的。來看 #1 —— Python 搜尋局部變量 x 失敗,然後在屬于另一個函數的外層作用域裡尋找。變量 x 是函數 outer 的局部變量,但函數 inner 仍然有外層作用域的通路權限(至少有讀和修改的權限)。在 #2 處調用函數 inner。值得注意的是,inner 在此處也隻是一個變量名,遵循 Python 的變量查找規則——Python 首先在 outer 的作用域查找并找到了局部變量 inner。

在 Python 中有個常識:函數和其他任何東西一樣,都是對象。函數包含變量,它并不那麼特殊。

也許你從未考慮過函數可以有屬性——但是函數在 Python 中,和其他任何東西一樣都是對象。(如果對此感覺困惑,稍後你會看到 Python 中的類也是對象,和其他任何東西一樣!)也許這有點學術的感覺——在 Python 中函數隻是正常的值,就像其他任意類型的值一樣。這意味着可以将函數當做實參傳遞給函數,或者在函數中将函數作為傳回值傳回。如果你從未想過這樣使用,請看下面的可執行代碼:

和其他變量一樣,函數名就是變量标簽.

再來看下面的例子:

這看起來也許有點怪異。在 #1 處傳回一個其實是函數标簽的變量 inner。也沒有什麼特殊文法——函數 outer 1傳回了并沒有被調用的函數 inner。還記得變量的生命周期嗎?每次調用函數 outer 的時候,函數 inner 會被重新定義,但是如果函數 outer1 沒有傳回 inner,當 inner 超出 outer 的作用域,inner 的生命周期将結束。在 #2 處将獲得傳回值即函數 inner,并指派給新變量 foo。

請參考專門的一片關于閉包的文章

裝飾器其實就是一個以函數作為參數并傳回一個替換函數的可執行函數。讓我們從簡單的開始,直到能寫出實用的裝飾器。

請仔細看這個裝飾器示例。首先,定義了一個帶單個參數 some_func 的名為 outer 的函數。然後在 outer 内部定義了一個内嵌函數 inner。inner 函數将列印一行字元串然後調用 some_func,并在 #1 處擷取其傳回值。在每次 outer 被調用時,some_func 的值可能都會不同,但不論 some_func 是什麼函數,都将調用它。最後,inner 傳回 some_func() 的傳回值加 1。在 #2 處可以看到,當調用指派給 decorated 的傳回函數時,得到的是一行文本輸出和傳回值 2。

我們可以說變量 decorated 是 foo 的裝飾版——即 foo 加上一些東西。

接着改寫

@符号是裝飾器的文法糖,在定義函數的時候使用

等價于

foo 函數被用作裝飾器,其本身接收一個函數對象作為參數,然後做一些工作後,傳回接收的參數,供外界調用。

注意: 時刻牢記 @foo 隻是一個文法糖,其本質是 foo = bar(foo)

@use_logging(level=’warn’) 調用的時候,python能夠發現這一層的封裝,并把參數傳遞到裝飾器中

所有的函數都是可調用對象。

一個類執行個體也可以變成一個可調用對象,隻需要實作一個特殊方法call()。

簡單來講就是将動态輸入的函數轉成内嵌函數所需要表達的内容

定義函數時使用 * 的用法意味着任何傳遞給函數的額外位置參數都是以 * 開頭的

星* 符号也可以用在函數調用時,在這裡它也有類似的意義。在調用函數時,以 * 開頭的變量表示該變量内容需被取出用做位置參數。再舉例如下:

在 #1 處的代碼和 #2 處的作用相同——可以手動做的事情,在 #2 處 Python 幫我們自動處理了。這看起來不錯,*args 可以表示在調用函數時從疊代器中取出位置參數, 也可以表示在定義函數時接收額外的位置參數。

接下來介紹稍微複雜一點的用來表示字典和鍵值對的 *,就像 用來表示疊代器和位置參數。

當定義一個函數時,使用 kwargs 來表示所有未捕獲的關鍵字參數将會被存儲在字典 kwargs 中。此前 args 和 kwargs 都不是 Python 中文法的一部分,但在函數定義時使用這兩個變量名是一種慣例。和 * 的使用一樣,可以在函數調用和定義時使用 。

<a href="http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html">http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html</a>