對于list胜臊、string鞋诗、tuple筒主、dict等這些容器對象,使用for循環(huán)遍歷是很方便的燥翅。在后臺for語句對容器對象調(diào)用iter()函數(shù)骑篙。iter()是Python內(nèi)置函數(shù)。
iter()會返回一個定義了next()方法的迭代器對象森书,它在容器中逐個訪問容器內(nèi)的元素靶端。next()也是python內(nèi)置函數(shù)谎势。在沒有后續(xù)元素時,next()會拋出一個StopIteration異常杨名,通知for語句循環(huán)結(jié)束脏榆。
1,迭代器協(xié)議:對象需要提供next()方法台谍,它要么返回迭代中的下一項须喂,要么就引起一個StopIteration異常,以終止迭代趁蕊。
2坞生,可迭代對象:實現(xiàn)了迭代器協(xié)議對象。list掷伙、tuple是己、dict都是Iterable(可迭代對象),但不是iteration(迭代器對象)任柜。但可以使用內(nèi)建函數(shù)iter()卒废,把這些都變成iteration(迭代器對象)。
# 隨便定義一個listlistArray=[1,2,3]# 使用iter()函數(shù)iterName=iter(listArray)print(iterName)# 結(jié)果如下:是一個列表list的迭代器# print(next(iterName))print(next(iterName))print(next(iterName))print(next(iterName))#沒有迭代到下一個元素乘盼,直接拋出異常# 1# 2# 3# Traceback (most recent call last):#? File "Test07.py", line 32, in # StopIteration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 計算出菲波那切數(shù)列classFib(object):def__init__(self, max):super(Fib, self).__init__()? ? ? ? self.max = maxdef__iter__(self):self.a =0self.b =1returnselfdef__next__(self):fib = self.aiffib > self.max:raiseStopIteration? ? ? ? self.a, self.b = self.b, self.a + self.breturnfib# 定義一個main函數(shù)升熊,循環(huán)遍歷每一個菲波那切數(shù)defmain():# 20以內(nèi)的數(shù)fib = Fib(20)foriinfib:? ? ? ? print(i)# 測試if__name__ =='__main__':? ? main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
解釋說明:
在本類的實現(xiàn)中,定義了一個iter(self)方法绸栅,這個方法是在for循環(huán)遍歷時被iter()調(diào)用级野,返回一個迭代器。因為在遍歷的時候粹胯,是直接調(diào)用的python內(nèi)置函數(shù)iter()蓖柔,由iter()通過調(diào)用iter(self)獲得對象的迭代器。有了迭代器风纠,就可以逐個遍歷元素了况鸣。而逐個遍歷的時候,也是使用內(nèi)置的next()函數(shù)通過調(diào)用對象的next(self)方法對迭代器對象進(jìn)行遍歷竹观。所以要實現(xiàn)iter(self)和next(self)镐捧。
而且因為實現(xiàn)了next(self),所以在實現(xiàn)iter(self)的時候臭增,直接返回self就可以懂酱。
總結(jié)一句話就是:在循環(huán)遍歷自定義容器對象時,會使用python內(nèi)置函數(shù)iter()調(diào)用遍歷對象的iter(self)獲得一個迭代器,之后再循環(huán)對這個迭代器使用next()調(diào)用迭代器對象的next(self)。
注意點:iter(self)只會被調(diào)用一次,而next(self)會被調(diào)用 n 次誊抛,直到出現(xiàn)StopIteration異常列牺。
>延遲操作。也就是在需要的時候才產(chǎn)生結(jié)果拗窃,不是立即產(chǎn)生結(jié)果瞎领。
>生成器是只能遍歷一次的泌辫。
第一類:生成器函數(shù):還是使用? def? 定義函數(shù),但是九默,使用yield而不是return語句返回結(jié)果震放。yield語句一次返回一個結(jié)果,在每個結(jié)果中間荤西,掛起函數(shù)的狀態(tài)澜搅,以便下次從它離開的地方繼續(xù)執(zhí)行伍俘。
如下案例加以說明:
# 菲波那切數(shù)列defFib(max):n, a, b =0,0,1whilen < max:yieldb? ? ? ? a, b = b, a + b? ? ? ? n = n +1return'親邪锌!沒有數(shù)據(jù)了...'# 調(diào)用方法,生成出10個數(shù)來f=Fib(10)# 使用一個循環(huán)捕獲最后return 返回的值癌瘾,保存在異常StopIteration的value中whileTrue:try:? ? ? ? x=next(f)? ? ? ? print("f:",x)exceptStopIterationase:? ? ? ? print("生成器最后的返回值是:",e.value)break
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
第二類:生成器表達(dá)式:類似于列表推導(dǎo)觅丰,只不過是把一對大括號[]變換為一對小括號()。但是妨退,生成器表達(dá)式是按需產(chǎn)生一個生成器結(jié)果對象妇萄,要想拿到每一個元素,就需要循環(huán)遍歷咬荷。
如下案例加以說明:
# 一個列表xiaoke=[2,3,4,5]# 生成器generator冠句,類似于list,但是是把[]改為()gen=(aforainxiaoke)foriingen:? ? print(i)#結(jié)果是:2345# 為什么要使用生成器幸乒?因為效率懦底。# 使用生成器表達(dá)式取代列表推導(dǎo)式可以同時節(jié)省 cpu 和 內(nèi)存(RAM)。# 如果你構(gòu)造一個列表(list)的目的僅僅是傳遞給別的函數(shù),# 比如 傳遞給tuple()或者set(), 那就用生成器表達(dá)式替代吧!# 本案例是直接把列表轉(zhuǎn)化為元組kk=tuple(aforainxiaoke)print(kk)#結(jié)果是:(2,3,4,5)# python內(nèi)置的一些函數(shù)罕扎,可以識別這是生成器表達(dá)式result1=sum(aforainrange(3))print(result1)# 列表推導(dǎo)式result2=sum([aforainrange(3)])print(result2)