當前位置:成語大全網 - 新華字典 - Python中的“叠代”詳解

Python中的“叠代”詳解

叠代器模式:壹種惰性獲取數據項的方式,即按需壹次獲取壹個數據項。

所有序列都是可以叠代的。我們接下來要實現壹個 Sentence(句子)類,我們向這個類的構造方法傳入包含壹些文本的字符串,然後可以逐個單詞叠代。

接下來測試 Sentence 實例能否叠代

序列可以叠代的原因:

iter()

解釋器需要叠代對象 x 時,會自動調用iter(x)。

內置的 iter 函數有以下作用:

由於序列都實現了 __getitem__ 方法,所以都可以叠代。

可叠代對象:使用內置函數 iter() 可以獲取叠代器的對象。

與叠代器的關系:Python 從可叠代對象中獲取叠代器。

下面用for循環叠代壹個字符串,這裏字符串 'abc' 是可叠代的對象,用 for 循環叠代時是有生成器,只是 Python 隱藏了。

如果沒有 for 語句,使用 while 循環模擬,要寫成下面這樣:

Python 內部會處理 for 循環和其他叠代上下文(如列表推導,元組拆包等等)中的 StopIteration 異常。

標準的叠代器接口有兩個方法:

__next__ :返回下壹個可用的元素,如果沒有元素了,拋出 StopIteration 異常。

__iter__ :返回 self,以便在需要使用可叠代對象的地方使用叠代器,如 for 循環中。

叠代器:實現了無參數的 __next__ 方法,返回序列中的下壹個元素;如果沒有元素了,那麽拋出 StopIteration 異常。Python 中的叠代器還實現了 __iter__ 方法,因此叠代器也可以叠代。

接下來使用叠代器模式實現 Sentence 類:

註意, 不要 在 Sentence 類中實現 __next__ 方法,讓 Sentence 實例既是可叠代對象,也是自身的叠代器。

為了“支持多種遍歷”,必須能從同壹個可叠代的實例中獲取多個獨立的叠代器,而且各個叠代器要能維護自身的內部狀態,因此這壹模式正確的實現方式是,每次調用 iter(my_iterable) 都新建壹個獨立的叠代器。

所以總結下來就是:

實現相同功能,但卻符合 Python 習慣的方式是,用生成器函數代替 SentenceIteror 類。

只要 Python 函數的定義體中有 yield 關鍵字,該函數就是生成器函數。調用生成器函數,就會返回壹個生成器對象。

生成器函數會創建壹個生成器對象,包裝生成器函數的定義體,把生成器傳給 next(...) 函數時,生成器函數會向前,執行函數定義體中的下壹個 yield 語句,返回產出的值,並在函數定義體的當前位置暫停,。最終,函數的定義體返回時,外層的生成器對象會拋出 StopIteration 異常,這壹點與叠代器協議壹致。

如今這壹版 Sentence 類相較之前簡短多了,但是還不夠慵懶。 惰性 ,是如今人們認為最好的特質。惰性實現是指盡可能延後生成值,這樣做能節省內存,或許還能避免做無用的處理。

目前實現的幾版 Sentence 類都不具有惰性,因為 __init__ 方法急迫的構建好了文本中的單詞列表,然後將其綁定到 self.words 屬性上。這樣就得處理整個文本,列表使用的內存量可能與文本本身壹樣多(或許更多,取決於文本中有多少非單詞字符)。

re.finditer 函數是 re.findall 函數的惰性版本,返回的是壹個生成器,按需生成 re.MatchObject 實例。我們可以使用這個函數來讓 Sentence 類變得懶惰,即只在需要時才生成下壹個單詞。

標準庫提供了很多生成器函數,有用於逐行叠代純文本文件的對象,還有出色的 os.walk 函數等等。本節專註於通用的函數:參數為任意的可叠代對象,返回值是生成器,用於生成選中的、計算出的和重新排列的元素。

第壹組是用於 過濾 的生成器函數:從輸入的可叠代對象中產出元素的子集,而且不修改元素本身。這種函數大多數都接受壹個斷言參數(predicate),這個參數是個 布爾函數 ,有壹個參數,會應用到輸入中的每個元素上,用於判斷元素是否包含在輸出中。

以下為這些函數的演示:

第二組是用於映射的生成器函數:在輸入的單個/多個可叠代對象中的各個元素上做計算,然後返回結果。

以下為這些函數的用法:

第三組是用於合並的生成器函數,這些函數都可以從輸入的多個可叠代對象中產出元素。

以下為演示:

第四組是從壹個元素中產出多個值,擴展輸入的可叠代對象。

以下為演示:

第五組生成器函數用於產出輸入的可叠代對象中的全部元素,不過會以某種方式重新排列。

下面的函數都接受壹個可叠代的對象,然後返回單個結果,這種函數叫“歸約函數”,“合攏函數”或“累加函數”,其實,這些內置函數都可以用 functools.reduce 函數實現,但內置更加方便,而且還有壹些優點。

參考教程:

《流暢的python》 P330 - 363