深入Python3 (Dive Into Python3)筆記6--閉合與生成器

一切內容都是摘抄,主要是便於回憶和鼓勵自己不要間斷,更詳細內容請見原帖地址:

《深入 python3 》中文版

http://woodpecker.org.cn/diveintopython3/index.html

 

 

6.1. 深入

6.2. 我知道,讓我們用正則表達式!

re.sub 替換 所有的 匹配項,而不僅僅是第一個匹配項。因此該正則表達式將 caps 轉換爲 oops,因爲無論是 c 還是 a 均被轉換爲 o 。

中括號表示“匹配這些字符的其中之一”。因此 [sxz] 的意思是: “s、 x 或 z”,但只匹配其中之一。

作爲方括號中的第一個字符, ^ 有特別的含義:非。[^abc] 的意思是:“ 除了 a、 b 或 c 之外的任何字符”。

re.sub('([^aeiou])y$', r'/1ies', 'vacancy')

順便,我還想指出可以將該兩條正則表達式合併起來(一條查找是否應用該規則,另一條實際應用規則),使其成爲一條正則表達式。它看起來是下面這個樣子:其中多數內容看起來應該很熟悉:使用了在 案例研究:分析電話號碼 中用到的記憶分組。該分組用於保存字母 y 之前的字符。然後在替換字符串中,用到了新的語法: /1,它表示“嘿,記住的第一個分組呢?把它放到這裏。”在此例中, 記住了 y 之前的 c ,在進行替換時,將用 c 替代 c,用 ies 替代 y 。(如果有超過一個的記憶分組,可以使用 /2 和 /3 等等。)

6.3. 函數列表

def match_default(noun):
    return True
 
def apply_default(noun):
    return noun + 's'
 
rules = ((match_sxz, apply_sxz), 
         (match_h, apply_h),
         (match_y, apply_y),
         (match_default, apply_default)
         )
 
def plural(noun):           
	for matches_rule, apply_rule in rules:
   		if matches_rule(noun):
			return apply_rule(noun)

現在有了一個 rules 數據結構——一個函數對的序列,而不是一個函數(plural())實現多個條規則。

由於所有的規則被分割成單獨的數據結構,新的 plural() 函數可以減少到幾行代碼。使用 for 循環,可以一次性從 rules 這個數據結構中取出匹配規則和應用規則這兩樣東西(一條匹配對應一條應用)。在 for 循環的第一次迭代過程中, matches_rule 將獲取 match_sxz,而 apply_rule 將獲取 apply_sxz。在第二次迭代中(假定可以進行到這一步), matches_rule 將會賦值爲 match_h,而 apply_rule 將會賦值爲 apply_h 。該函數確保最終能夠返回某個值,因爲終極匹配規則 (match_default) 只返回 True,意思是對應的應用規則 (apply_default) 將總是被應用。

該技術能夠成功運作的原因是 Python 中一切都是對象,包括了函數。數據結構 rules 包含了函數——不是函數的名稱,而是實際的函數對象。

6.4. 匹配模式列表

build_match_and_apply_functions() 函數用於動態創建其它函數。它接受 pattern、 search 和 replace 三個參數,並定義了 matches_rule() 函數,該函數通過傳給 build_match_and_apply_functions() 函數的 pattern 及傳遞給所創建的 matchs_rules() 函數的 word 調用 re.search() 函數,哇。

在動態函數中使用外部參數值的技術稱爲 閉合【closures】。基本上,常量的創建工作都在創建應用函數過程中完成:它接受一個參數 (word),但實際操作還加上了另外兩個值(search 和 replace),該兩個值都在定義應用函數時進行設置。

6.5. 匹配模式文件

全局的 open() 函數打開文件並返回一個文件對象。此例中,將要打開的文件包含了名詞複數形式的模式字符串。with 語句創建了叫做 context【上下文】的東西:當 with 塊結束時,Python 將自動關閉文件,即便是在 with 塊中引發了例外也會這樣。

split() 方法的第一個參數是 None,表示“對任何空白字符進行分隔(製表符或空白,沒有區別)”。第二個參數是 3,意思是“針對空白分隔三次,丟棄該行剩下的部分。”像 [sxz]$ $ es 這樣的行將被分割爲列表 ['[sxz]$', '$', 'es'],意思是 pattern 獲得值 '[sxz]$', search 獲得值 '$',而 replace 獲得值 'es'。

此處的改進是將複數形式規則獨立地放到了一份外部文件中,因此可獨立於使用它的代碼單獨對規則進行維護。代碼是代碼,數據是數據,生活更美好。

6.6. 生成器

make_counter 中出現的 yield 命令的意思是這不是一個普通的函數。它是一次生成一個值的特殊類型函數。可以將其視爲可恢復函數。調用該函數將返回一個可用於生成連續 x 值的 生成器【Generator】。

next() 函數以一個生成器對象爲參數,並返回其下一個值。對 counter 生成器第一次調用 next() ,它針對第一條 yield 語句執行 make_counter() 中的代碼,然後返回所產生的值。在此情況下,該代碼輸出將爲 2,因其僅通過調用 make_counter(2) 對生成器進行初始創建。

對同一生成器對象反覆調用 next() 將確切地從上次調用的位置開始繼續,直到下一條 yield 語句。所有的變量、局部數據等內容在 yield 時被保存,在 next() 時被恢復。下一行代碼等待被執行以調用 print() 以打印出 incrementing x 。之後,執行語句 x = x + 1。然後它繼續通過 while 再次循環,而它再次遇上的第一條語句是 yield x,該語句將保存所有一切狀態,並返回當前 x 的值(當前爲 3)。

“yield” 暫停一個函數。“next()” 從其暫停處恢復其運行。

6.6.1. 斐波那奇生成器

可以在 for 循環中直接使用像 fib() 這樣的生成器。for 循環將會自動調用 next() 函數,從 fib() 生成器獲取數值並賦值給 for 循環索引變量。(n)

這是一個很有用的用法:將一個生成器傳遞給 list() 函數,它將遍歷整個生成器(就像前例中的 for 循環)並返回所有數值的列表。

6.6.2. 複數規則生成器

通過第四步獲得了什麼呢?啓動時間。在第四步中引入 plural4 模塊時,它讀取了整個模式文件,並創建了一份所有可能規則的列表,甚至在考慮調用 plural() 函數之前。有了生成器,可以輕鬆地處理所有工作:可以讀取規則,創建函數並試用它們,如果該規則可用甚至可以不讀取文件剩下的部分或創建更多的函數。

失去了什麼?性能!每次調用 plural() 函數,rules() 生成器將從頭開始——這意味着重新打開模式文件,並從頭開始讀取,每次一行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章