Python中使用內層函式的好處

艾凌風發表於2015-07-05

內層函式——它們的優點是什麼?

讓我們看一下寫內層函式的三個常見原因。

記住:在Python中,函式是“一等公民”,這意味著它們和其他物件平起平坐(例如:整型,字串,列表,模組等)。你可以動態地建立和銷燬它們,把它們傳遞給其他函式,把它們作為值返回,等等。

本文使用Python 3.4.1版本

1.封裝

你使用內層函式來保護它們不受函式外部變化的影響,也就是說把它們從全域性作用域藏起來。

這裡有一個簡單的例子來強調這一概念:

嘗試呼叫inner_increment()函式

現在,把inner_increment的呼叫註釋掉,再把對外部函式呼叫的註釋取消,outer(10),把10作為引數傳入:

請記住這僅僅是一個例子,儘管程式碼得到了期望的結果,但是使用一個前置的下劃線把inner_increment()函式變為“私有”函式:_inner_increment()更好。

下面這個遞迴的例子與使用巢狀函式相比稍微好一些:

同樣測試一下這段程式碼。使用這種設計模式的一個主要優勢在於:在外部函式中對全部引數執行了檢查,你可以在內部函式中跳過全部的檢查過程。

關於這個遞迴更加詳細的解釋請看Problem Solving with Algorithms and Data Structures

2.貫徹DRY(Don’t Repeat Yourself )原則

也許你有一個巨型函式,在很多很多地方執行一大段的程式碼。比如,你可能寫了一個函式用來處理檔案,並且你希望它既可以接受一個開啟檔案物件或是一個檔名:

同樣,通常會把do_stuff()作為一個頂層私有函式,但是如果你想要把它作為一個內層函式隱藏起來,你也可以這樣做。

來個實際的例子怎麼樣?

讓我們假設你想知道紐約市全部WiFi熱點的數量。而且確實有提供這些資訊的原始資料: 資料

訪問這個網站並下載CSV.

執行函式:

3.閉包和工廠函式

現在我們要談到使用內層函式最重要的原因了。目前為止我們看到的全部內層函式的例子都是普通函式,只不過它們湊巧巢狀在另外的函式之中了。換句話說,我們本可以用另外的方式定義這些函式(正如我們談到的那樣),並沒有什麼特別的理由去巢狀它們。

但是當我們談到閉包的時候,情況就不一樣了:你必須要利用巢狀函式。

什麼是閉包?

閉包無非是使內層函式在呼叫時記住它當前環境的狀態。初學者經常認為閉包就是內層函式,而且實際上它是由內層函式導致的。閉包在棧上“封閉”了區域性變數,使其在棧建立執行結束後仍然存在。

一個例子

此處發生了什麼?

  1. generate_power()函式是一個工廠方法——簡單說就是意味著它每次呼叫的時候會建立一個新函式,並返回這個新建立的函式,因此raise_tworaise_three 都是新建立的函式。
  2. 這個新的內層函式做了什麼呢?它接受一個單獨的引數,power,並且返回number**power
  3. 內層函式從哪得到number的值呢?這就該閉包登場了:nth_power()從外層函式得到power 的值,讓我們逐步檢視這一過程:
    • 呼叫外層函式:generate_power(2)
    • 生成一個nth_power()函式,它接受一個單一的引數power
    • 儲存nth_power()的狀態快照,其中number=2
    • 把這個快照傳入generate_power()函式
    • 返回nth_power()函式

換句話說,閉包函式“初始化”了nth_power()函式並將其返回。現在無論你何時呼叫這個新返回的函式,它都會去檢視其私有的快照,也就是包含power=2的那一個。

現實世界

來一個實際例子如何?

這是一個簡化過的函式,用來檢查某個特定使用者是否有許可權訪問特定的頁面。你可以很容易的修改它從會話中抓取使用者資訊,檢視他們是否具有訪問當前路徑的正確憑證。我們可以查詢資料庫來檢視許可情況,然後根據是否具有正確的憑證來返回返回正確的檢視,而不是檢查user是否等於‘Admin’。

結論

閉包和工廠函式是內層函式最常見也最強大的用途。在大多數情況下,當你看到一個被裝飾的函式,裝飾器就是一個工程函式,它接受一個函式作為引數,然後返回一個新的函式,其閉包中包含了原函式。停一停。深呼吸。喝口咖啡。再讀一遍。

換句話說,裝飾器是一個語法糖,用來實現generate_power() 例子中提到的功能

我把這個例子留給你:

如果你的程式碼編輯器執行,請並排對比著檢視generate_power(exponent)generate_power(number)這兩個函式來搞清楚我們所討論的概念。(比如說Sublime Text有分欄瀏覽模式(譯註:shift+alt+2))

如何你還沒有編寫這兩個函式,開啟編輯器並開始編寫。對於新手程式設計師來講,編碼是一項親手實踐的活動,就像學習騎車,你必須去做才行——而且要獨立完成。所以請回到手上的任務來。當你輸入完成程式碼後,你可以清楚的看到它們產生了相同的結果,但是這之間是有不同的。對於那些從來沒用過裝飾器的人來說,注意到這些不同是理解它們的第一步——如果你要走這條路的話。

打賞支援我翻譯更多好文章,謝謝!

打賞譯者

打賞支援我翻譯更多好文章,謝謝!

任選一種支付方式

Python中使用內層函式的好處 Python中使用內層函式的好處

相關文章