作者:豌豆花下貓 來自:Python貓 鏈接:https://mp.weixin.qq.com/s/7MbRCn37fIIN42rLm6ho3g 在軟件開發(fā)領(lǐng)域中,人們經(jīng)常會(huì)用到這一個(gè)概念——“設(shè)計(jì)模式”(design pattern),,它是一種針對(duì)軟件設(shè)計(jì)的共性問題而提出的解決方案,。在一本圣經(jīng)級(jí)的書籍《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》(1991年,Design Patterns - Elements of Reusable Object-Oriented Software)中,,它提出了23種設(shè)計(jì)模式,。迭代器模式就是其中的一種,在各種編程語言中都得到了廣泛的應(yīng)用,。 本文將談?wù)?Python 中的迭代器模式,,主要內(nèi)容:什么是迭代器模式,、Python 如何實(shí)現(xiàn)迭代器模式,、itertools 模塊創(chuàng)建迭代器的方法,、其它運(yùn)用迭代器的場(chǎng)景等等,期待與你共同學(xué)習(xí)進(jìn)步,。 1、什么是迭代器模式?維基百科有如下定義:
簡(jiǎn)單地說,,迭代器模式就是一種通用性的可以遍歷容器類型(如序列類型、集合類型等)的實(shí)現(xiàn)方式,。使用迭代器模式,,可以不關(guān)心遍歷的對(duì)象具體是什么(如字符串、列表,、字典等等),,也不需要關(guān)心遍歷的實(shí)現(xiàn)算法是什么,它關(guān)心的是從容器中遍歷/取出元素的結(jié)果,。 按遍歷方式劃分,,迭代器可分為內(nèi)部迭代器與外部迭代器,它們的區(qū)別在于執(zhí)行迭代動(dòng)作與維持迭代狀態(tài)的不同,。 通常而言,,迭代器是一次性的,當(dāng)?shù)^一輪后,,再次迭代將獲取不到元素,。 2、Python的迭代器模式由于迭代器模式的使用太常見了,,所以大多數(shù)編程語言都給常見的容器類型實(shí)現(xiàn)了它,,例如 Java 中的 Collection,List,、Set,、Map等。在 Java 中使用迭代器遍歷 List 可這么寫: List<String> list = new ArrayList<>(); ArrayList 類通過自身的 iterator() 方法獲得一個(gè)迭代器 iterator,,然后由該迭代器實(shí)例來落實(shí)遍歷過程,。 Python 當(dāng)然也應(yīng)用了迭代器模式,但它的實(shí)現(xiàn)思路跟上例卻不太一樣,。 首先,,Python 認(rèn)為遍歷容器類型并不一定要用到迭代器,因此設(shè)計(jì)了可迭代對(duì)象,。
上例中的 list 是可迭代對(duì)象(Iterable),,但并不是迭代器(雖然在底層實(shí)現(xiàn)時(shí)用了迭代器的部分思想),。Python 抓住了迭代器模式的本質(zhì),即是“迭代”,,賦予了它極高的地位,。 如此設(shè)計(jì)的好處顯而易見:(1)寫法簡(jiǎn)便,用意直白,;(2)可重復(fù)迭代,,避免一次性迭代器的缺陷;(3)不需要?jiǎng)?chuàng)建迭代器,,減少開銷,。 可迭代對(duì)象可看作是廣義的迭代器,同時(shí),,Python 也設(shè)計(jì)了普通意義的狹義的迭代器,。 list = [1,2,3,4] 上例中的 iter() 方法會(huì)將可迭代對(duì)象變成一個(gè)迭代器。從輸出結(jié)果可以看出,,該迭代器的迭代過程是一次性的,。 由此看來,Python 其實(shí)是將“迭代器模式”一拆為二來實(shí)現(xiàn):一是可迭代思想,,廣泛播種于容器類型的對(duì)象中,,使它們都可迭代;一是迭代器,,一種特殊的可迭代對(duì)象,承擔(dān)普通意義上的迭代器所特有的迭代任務(wù),。 同時(shí),,它還提供了將可迭代對(duì)象轉(zhuǎn)化為迭代器的簡(jiǎn)易方法,如此安排,,真是將迭代器模式的效力發(fā)揮到了極致,。 3、創(chuàng)建迭代器創(chuàng)建迭代器有如下方式:(1)iter() 方法,,將可迭代對(duì)象轉(zhuǎn)化成迭代器,;(2) 四類方法各有適用場(chǎng)所,,本節(jié)重點(diǎn)介紹 itertools 模塊,。它可以創(chuàng)建三類迭代器:無限迭代器、有限迭代器與組合迭代器,。 3.1 無限迭代器
3.2 有限迭代器以上方法,比較常用的有:chain() 將多個(gè)可迭代對(duì)象(可以是不同類型)連接成一個(gè)大迭代器,;compress() 方法根據(jù)真假過濾器篩選元素,;groupby() 把迭代器中相鄰的重復(fù)元素挑出來放在一起;islice() 方法返回迭代器切片,;tee() 方法根據(jù)可迭代對(duì)象創(chuàng)建 n 個(gè)(默認(rèn)2個(gè))迭代器副本,。 for c in itertools.chain('ABC', [1,2,3]): 3.3 組合迭代器product() :求解多個(gè)可迭代對(duì)象的笛卡爾積。 permutations() :求解可迭代對(duì)象的元素的排列,。 combinations():求解可迭代對(duì)象的元素的組合,。
4、強(qiáng)大的內(nèi)置迭代器方法迭代器模式的使用場(chǎng)景實(shí)在太普遍了,,而 Python 也為迭代器的順利使用而提供了很多便利的條件,,本節(jié)將介紹相關(guān)的幾個(gè)內(nèi)置方法。這些方法非常常用而且強(qiáng)大,,是 Python 進(jìn)階的必會(huì)內(nèi)容,。 4.1 zip() 方法zip() 方法可以同時(shí)迭代多個(gè)序列,并各取一個(gè)元素,,生成一個(gè)可返回元組的迭代器,。此迭代器的長(zhǎng)度以較短序列的長(zhǎng)度保持一致,若想生成較長(zhǎng)序列的長(zhǎng)度,,需要使用 itertools 模塊的 zip_longest() 方法,。 import itertools 4.2 enumerate() 方法enumerate() 方法接收一個(gè)序列類型參數(shù),生成一個(gè)可返回元組的迭代器,,元組內(nèi)容是下標(biāo)及其對(duì)應(yīng)的元素值,。它還可接收一個(gè)可選參數(shù),指定下標(biāo)的起始值,,默認(rèn)是0 ,。 注意:眾所周知,Python 中序列的索引值從 0 開始,,但是,,enumerate() 可以達(dá)到改變起始索引數(shù)值的效果,。
4.3 map() 方法map() 方法的參數(shù)是一個(gè)函數(shù)及一個(gè)或多個(gè)可迭代對(duì)象,它會(huì)將可迭代對(duì)象的元素映射到該函數(shù)中,,然后迭代地運(yùn)行該函數(shù),,返回結(jié)果也是一個(gè)迭代器。當(dāng)存在多個(gè)可迭代對(duì)象參數(shù)時(shí),,迭代長(zhǎng)度等于較短對(duì)象的長(zhǎng)度,。 def square(x): 4.4 filter() 方法filter() 方法的參數(shù)是一個(gè)判斷函數(shù)及一個(gè)可迭代對(duì)象,遍歷可迭代對(duì)象執(zhí)行判斷函數(shù),,過濾下判斷為True 的元素,,與它相對(duì),若想保留判斷為 False 的元素,,可使用 itertoole 模塊的 filterfalse() 方法,。
5. 小結(jié)迭代器模式幾乎是 23 種設(shè)計(jì)模式中最常用的設(shè)計(jì)模式,本文主要介紹了 Python 是如何運(yùn)用迭代器模式,,并介紹了 itertools 模塊生成迭代器的 18 種方法,,以及 5 種生成迭代器的內(nèi)置方法。 |
|