摘要:抓住了迭代器模式的本質(zhì),即是迭代,賦予了它極高的地位。輸出結(jié)果輸出結(jié)果小結(jié)迭代器模式幾乎是種設(shè)計(jì)模式中最常用的設(shè)計(jì)模式,本文主要介紹了是如何運(yùn)用迭代器模式,并介紹了模塊生成迭代器的種方法,以及種生成迭代器的內(nèi)置方法。
在軟件開發(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)用迭代器的場景等等,期待與你共同學(xué)習(xí)進(jìn)步。
1、什么是迭代器模式?維基百科有如下定義:
迭代器是一種最簡單也最常見的設(shè)計(jì)模式。它可以讓用戶透過特定的接口巡訪容器中的每一個(gè)元素而不用了解底層的實(shí)現(xià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 可以這么寫:
Listlist = new ArrayList<>(); Iterator iterator = list.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); }
ArrayList 類通過自身的 iterator() 方法獲得一個(gè)迭代器 iterator,然后由該迭代器實(shí)例來落實(shí)遍歷過程。
Python 當(dāng)然也應(yīng)用了迭代器模式,但它的實(shí)現(xiàn)思路跟上例卻不太一樣。
首先,Python 認(rèn)為遍歷容器類型并不一定要用到迭代器,因此設(shè)計(jì)了可迭代對(duì)象。
list = [1,2,3,4] for i in list: print(i,end=" ") # 1 2 3 4 for i in list: print(i,end=" ") # 1 2 3 4
上例中的 list 是可迭代對(duì)象(Iterable),但并不是迭代器(雖然在底層實(shí)現(xiàn)時(shí)用了迭代器的部分思想)。Python 抓住了迭代器模式的本質(zhì),即是“迭代”,賦予了它極高的地位。
如此設(shè)計(jì)的好處顯而易見:(1)寫法簡便,用意直白;(2)可重復(fù)迭代,避免一次性迭代器的缺陷;(3)不需要?jiǎng)?chuàng)建迭代器,減少開銷。
可迭代對(duì)象可看作是廣義的迭代器,同時(shí),Python 也設(shè)計(jì)了普通意義的狹義的迭代器。
list = [1,2,3,4] it = iter(list) for i in it: print(i,end=" ") # 1 2 3 4 for i in it: print(i,end=" ") # 無輸出
上例中的 iter() 方法會(huì)將可迭代對(duì)象變成一個(gè)迭代器。從輸出結(jié)果可以看出,該迭代器的迭代過程是一次性的。
由此看來,Python 其實(shí)是將“迭代器模式”一拆為二來實(shí)現(xiàn):一是可迭代思想,廣泛播種于容器類型的對(duì)象中,使它們都可迭代;一是迭代器,一種特殊的可迭代對(duì)象,承擔(dān)普通意義上的迭代器所特有的迭代任務(wù)。
同時(shí),它還提供了將可迭代對(duì)象轉(zhuǎn)化為迭代器的簡易方法,如此安排,真是將迭代器模式的效力發(fā)揮到了極致。(關(guān)于可迭代對(duì)象與迭代器的更多區(qū)別、以及它們的實(shí)現(xiàn)原理,請(qǐng)參見《Python進(jìn)階:迭代器與迭代器切片》)
3、創(chuàng)建迭代器創(chuàng)建迭代器有如下方式:(1)iter() 方法,將可迭代對(duì)象轉(zhuǎn)化成迭代器;(2)__iter__() 與 __next__() 魔術(shù)方法,定義類實(shí)現(xiàn)這兩個(gè)魔術(shù)方法;(3)itertools 模塊,使用內(nèi)置模塊生成迭代器;(4)其它創(chuàng)建方法,如 zip() 、map() 、enumerate() 等等。
四類方法各有適用場所,本節(jié)重點(diǎn)介紹 itertools 模塊。它可以創(chuàng)建三類迭代器:無限迭代器、有限迭代器與組合迭代器。
3.1 無限迭代器count(start=0, step=1) :創(chuàng)建一個(gè)從 start (默認(rèn)值為 0) 開始,以 step (默認(rèn)值為 1) 為步長的的無限整數(shù)迭代器。
cycle(iterable) :對(duì)可迭代對(duì)象的元素反復(fù)執(zhí)行循環(huán)。
repeat(object [,times]) :反復(fù)生成 object 至無限,或者到給定的 times 次。
import itertools co = itertools.count() cy = itertools.cycle("ABC") re = itertools.repeat("A", 30) # 注意:請(qǐng)分別執(zhí)行;以下寫法未加終止判斷,只能按 Ctrl+C 退出 for n in co: print(n,end=" ") # 0 1 2 3 4...... for n in cy: print(n,end=" ") # A B C A B C A B...... for n in re: print(n,end=" ") # A A A A A A A A....(30個(gè))3.2 有限迭代器
以上方法,比較常用的有:chain() 將多個(gè)可迭代對(duì)象(可以是不同類型)連接成一個(gè)大迭代器;compress() 方法根據(jù)真假過濾器篩選元素;groupby() 把迭代器中相鄰的重復(fù)元素挑出來放在一起;islice() 方法返回迭代器切片(用法參見《Python進(jìn)階:迭代器與迭代器切片》);tee() 方法根據(jù)可迭代對(duì)象創(chuàng)建 n 個(gè)(默認(rèn)2個(gè))迭代器副本。
for c in itertools.chain("ABC", [1,2,3]): print(c,end=" ") # 輸出結(jié)果:A B C 1 2 3 for c in itertools.compress("ABCDEF", [1, 1, 0, 1, 0, 1]): print(c,end=" ") # 輸出結(jié)果:A B D F for key, group in itertools.groupby("aaabbbaaccd"): print(key, ":", list(group)) # 輸出結(jié)果: a : ["a", "a", "a"] b : ["b", "b", "b"] a : ["a", "a"] c : ["c", "c"] d : ["d"] itertools.tee("abc", 3) # 輸出結(jié)果:(3.3 組合迭代器, , )
product() :求解多個(gè)可迭代對(duì)象的笛卡爾積。
permutations() :求解可迭代對(duì)象的元素的全排列。
combinations():求解可迭代對(duì)象的元素的組合。
for i in itertools.product("ABC", [1,2]): print(i, end=" ") # 輸出結(jié)果:("A", 1) ("A", 2) ("B", 1) ("B", 2) ("C", 1) ("C", 2) for i in itertools.permutations("ABC", 2): print(i, end=" ") # 輸出結(jié)果:("A", "B") ("A", "C") ("B", "A") ("B", "C") ("C", "A") ("C", "B") for i in itertools.combinations("ABC", 2): print(i, end=" ") # 輸出結(jié)果:("A", "B") ("A", "C") ("B", "C") for i in itertools.combinations("ABCD", 3): print(i, end=" ") # 輸出結(jié)果:("A", "B", "C") ("A", "B", "D") ("A", "C", "D") ("B", "C", "D")4、強(qiáng)大的內(nèi)置迭代器方法
迭代器模式的使用場景實(shí)在太普遍了,而 Python 也為迭代器的順利使用而提供了很多便利的條件,本節(jié)將介紹相關(guān)的幾個(gè)內(nèi)置方法。這些方法非常常用而且強(qiáng)大,是 Python 進(jìn)階的必會(huì)內(nèi)容。
4.1 zip() 方法zip() 方法可以同時(shí)迭代多個(gè)序列,并各取一個(gè)元素,生成一個(gè)可返回元組的迭代器。此迭代器的長度以較短序列的長度保持一致,若想生成較長序列的長度,需要使用 itertools 模塊的 zip_longest() 方法。
import itertools a = [1, 2, 3] b = ["w", "x", "y", "z"] for i in zip(a,b): print(i,end=" ") # (1, "w") (2, "x") (3, "y") # 空缺值以 None 填補(bǔ) for i in itertools.zip_longest(a,b): print(i,end=" ") # (1, "w") (2, "x") (3, "y") (None, "z")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ù)值的效果。
seasons = ["Spring", "Summer", "Fall", "Winter"] for i in enumerate(seasons): print(i,end=" ") #輸出結(jié)果:(0, "Spring") (1, "Summer") (2, "Fall") (3, "Winter") for i in enumerate(seasons, start=7): print(i,end=" ") #輸出結(jié)果:(7, "Spring") (8, "Summer") (9, "Fall") (10, "Winter")4.3 map() 方法
map() 方法的參數(shù)是一個(gè)函數(shù)及一個(gè)或多個(gè)可迭代對(duì)象,它會(huì)將可迭代對(duì)象的元素映射到該函數(shù)中,然后迭代地運(yùn)行該函數(shù),返回結(jié)果也是一個(gè)迭代器。當(dāng)存在多個(gè)可迭代對(duì)象參數(shù)時(shí),迭代長度等于較短對(duì)象的長度。
def square(x): return x ** 2 l = map(square, [1, 2, 3, 4, 5]) print(list(l)) # 輸出結(jié)果:[1, 4, 9, 16, 25] m = map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10, 2]) print(list(m)) # 輸出結(jié)果:[3, 7, 11, 15, 19]4.4 filter() 方法
filter() 方法的參數(shù)是一個(gè)判斷函數(shù)及一個(gè)可迭代對(duì)象,遍歷可迭代對(duì)象執(zhí)行判斷函數(shù),過濾下判斷為True 的元素,與它相對(duì),若想保留判斷為 False 的元素,可使用 itertoole 模塊的 filterfalse() 方法。
import itertools fi = filter(lambda x: x%2, range(10)) ff = itertools.filterfalse(lambda x: x%2, range(10)) for i in fi: print(i,end=" ") # 輸出結(jié)果:1 3 5 7 9 for i in ff: print(i,end=" ") # 輸出結(jié)果:0 2 4 6 85. 小結(jié)
迭代器模式幾乎是 23 種設(shè)計(jì)模式中最常用的設(shè)計(jì)模式,本文主要介紹了 Python 是如何運(yùn)用迭代器模式,并介紹了 itertools 模塊生成迭代器的 18 種方法,以及 5 種生成迭代器的內(nèi)置方法。
相關(guān)鏈接:
itertools模塊文檔:http://t.cn/R6cGtfw
Python進(jìn)階:迭代器與迭代器切片
Python進(jìn)階:全面解讀高級(jí)特性之切片!
-----------------
本文原創(chuàng)并首發(fā)于微信公眾號(hào)【Python貓】,后臺(tái)回復(fù)“愛學(xué)習(xí)”,免費(fèi)獲得20+本精選電子書。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/25047.html
摘要:抓住了迭代器模式的本質(zhì),即是迭代,賦予了它極高的地位。輸出結(jié)果輸出結(jié)果小結(jié)迭代器模式幾乎是種設(shè)計(jì)模式中最常用的設(shè)計(jì)模式,本文主要介紹了是如何運(yùn)用迭代器模式,并介紹了模塊生成迭代器的種方法,以及種生成迭代器的內(nèi)置方法。 showImg(https://segmentfault.com/img/bVbmv7W?w=4272&h=2848); 在軟件開發(fā)領(lǐng)域中,人們經(jīng)常會(huì)用到這一個(gè)概念——設(shè)...
閱讀 1680·2021-09-26 10:00
閱讀 2941·2021-09-06 15:00
閱讀 3548·2021-09-04 16:40
閱讀 2312·2019-08-30 15:44
閱讀 724·2019-08-30 10:59
閱讀 1892·2019-08-29 18:34
閱讀 3625·2019-08-29 15:42
閱讀 2299·2019-08-29 15:36