python_魔法方法(六):迭代器和生成器
迭代器
自始至終,都有一個(gè)概念一直在用,但是我們卻沒(méi)來(lái)都沒(méi)有人在的深入剖析它。這個(gè)概念就是迭代。
迭代的意思有點(diǎn)類(lèi)似循環(huán),每一次的重復(fù)的過(guò)程被稱(chēng)為迭代的過(guò)程,而每一次迭代得到的結(jié)果會(huì)被用來(lái)作為下一次迭代的初始值。提供迭代方法的容器稱(chēng)為迭代器,通常接觸的迭代器有序列(列表、元組、字符串)還有字典也是迭代器,都支持迭代的操作。舉個(gè)列子,通常使用for循環(huán)進(jìn)行迭代。
>>> for i in "python":print(i)打印結(jié)果 p y t h o n字符串就是一個(gè)容器,同時(shí)也是一個(gè)迭代器,for語(yǔ)句的作用就是觸發(fā)這個(gè)迭代器的迭代功能,每次從容器里面依次拿出一個(gè)數(shù)據(jù)就,這就是迭代操作。
字典和文件也是支持迭代操作的:
>>> list1 = {"python":"python3.x",\"go":"go是一種語(yǔ)言語(yǔ)法",\"int":"python關(guān)鍵字",\} >>> for i in list1:print("%s --> %s"%(i,list1[j]))>>> for i in list1:print("%s --> %s"%(i,list1[i]))打印結(jié)果;
python --> python3.x
go --> go是一種語(yǔ)言語(yǔ)法
int --> python關(guān)鍵字
關(guān)于迭代,python還提供了兩個(gè)BIF:iter()? next()
對(duì)一個(gè)容器對(duì)象調(diào)用iter()就得到它的迭代器,調(diào)用next()迭代器就會(huì)返回下一個(gè)值,然后怎么結(jié)束了?如果迭代器沒(méi)有值可以返回,python將拋出一個(gè)叫做Stoplteration的異常。
>>> string = "python" >>> it = iter(string) >>> next(it) 'p' >>> next(it) 'y' >>> next(it) 't' >>> next(it) 'h' >>> next(it) 'o' >>> next(it) 'n' >>> next(it) Traceback (most recent call last):File "<pyshell#26>", line 1, in <module>next(it) StopIteration所以,利用這兩個(gè)BIF,可以分析出for語(yǔ)句其實(shí)就是這么工作的:
>>> string = "python" >>> it = iter(string) >>> while True:try:each = next(it)except StopIteration:breakprint(each)p y t h o n那么實(shí)現(xiàn)迭代器的魔法方法就有兩個(gè):__iter__()? ?__next__()
一個(gè)容器如果是迭代器,就必須實(shí)現(xiàn)__iter__()方法,這個(gè)方法實(shí)際上就是返回迭代器本身。接下來(lái)就是重點(diǎn)實(shí)現(xiàn)的是__next__()魔法方法,因?yàn)樗麤Q定了迭代器的規(guī)則,看一段例子:
>>> class Fibs():def __init__(self):self.a = 0self.b = 1def __iter__(self):return selfdef __next__(self):self.a,self.b = self.b,self.a+self.breturn self.a>>> fibs = Fibs() >>> for i in fibs:if i < 20:print(i)else:break1 1 2 3 5 8 13這個(gè)迭代器的唯一亮點(diǎn)就是沒(méi)有終點(diǎn),所以如果沒(méi)有跳出循環(huán),它會(huì)不斷迭代下去。那么就可以加一個(gè)參數(shù),用于控制迭代的范圍。
>>> class Fibs():def __init__(self,n = 20):self.a = 0self.b = 1self.n = ndef __iter__(self):return selfdef __next__(self):self.a,self.b = self.b,self.a+self.bif self.a > self.n:raise StopIterationreturn self.a>>> fibs = Fibs() >>> for i in fibs:print(i)1 1 2 3 5 8 13生成器
前面是迭代器,下面來(lái)說(shuō)生成器
生成器其實(shí)就是迭代器的一種實(shí)現(xiàn),那既然迭代器就可以實(shí)現(xiàn),為何還要生成器了?生成器之所以存在就是為了是python更為簡(jiǎn)潔,因?yàn)榈餍枰覀冏约喝ザx一個(gè)類(lèi)和實(shí)現(xiàn)相關(guān)的方法,而生成器則需要在普通函數(shù)中加一個(gè)yield語(yǔ)句即可。
生成器的發(fā)明,使python模仿協(xié)同程序的概念得以實(shí)現(xiàn),所謂協(xié)同程序,就是可以運(yùn)行的獨(dú)立函數(shù)調(diào)用,函數(shù)可以暫停或者掛起,并需要的時(shí)候從程序離開(kāi)的地方繼續(xù)或重新開(kāi)始。
對(duì)于調(diào)用一個(gè)普通的python函數(shù),一般是從函數(shù)的第一行代碼開(kāi)始執(zhí)行,結(jié)束與return語(yǔ)句,異常或函數(shù)所有語(yǔ)句執(zhí)行完畢,一但函數(shù)將控制權(quán)交給調(diào)用者,就意味著全部結(jié)束。函數(shù)中做的所有工作以及保存在局部變量中的數(shù)據(jù)將丟失。再次調(diào)用這個(gè)函數(shù)時(shí)一切都將從頭創(chuàng)建。
python是通過(guò)生成器來(lái)實(shí)現(xiàn)類(lèi)似于協(xié)同程序的概念:生成器可以暫時(shí)掛起函數(shù),并保留函數(shù)的局部變量等數(shù)據(jù),然后在再次調(diào)用他的時(shí)候,從上次暫停的位置繼續(xù)執(zhí)行下去。
舉個(gè)例子:
>>> def myGen():print("生成器被執(zhí)行!")yield 1yield 2>>> myG = myGen() >>> next(myG) 生成器被執(zhí)行! 1 >>> next(myG) 2 >>> next(myG) Traceback (most recent call last):File "<pyshell#76>", line 1, in <module>next(myG) StopIteration通過(guò)例子,當(dāng)函數(shù)結(jié)束的時(shí)候,一個(gè)StopIteration異常就會(huì)被拋出。由于Python的for循環(huán)會(huì)自動(dòng)調(diào)用next()方法和處理StopIteration異常,所以for循環(huán)當(dāng)然也是可以對(duì)生成器產(chǎn)生作用的:
>>> def myGen():print("生成器被執(zhí)行!")yield 1yield 2>>> myG = myGen() >>> for i in myG:print(i)生成器被執(zhí)行! 1 2前面說(shuō)的斐波那契數(shù)列例子,也可以用生成器實(shí)現(xiàn):
>>> def fibs():a,b = 0,1while True:a,b = b,a+byield a>>> for i in fibs():if i>100:breakprint(i)1 1 2 3 5 8 13 21 34 55 89寫(xiě)到現(xiàn)在,可以很好的用類(lèi)別推導(dǎo)式了,哈哈,先來(lái)看下下面的什么意思吧
>>> a = [i for i in range(100) if not (i%2) and i%3] >>> print(a) [2, 4, 8, 10, 14, 16, 20, 22, 26, 28, 32, 34, 38, 40, 44, 46, 50, 52, 56, 58, 62, 64, 68, 70, 74, 76, 80, 82, 86, 88, 92, 94, 98]含義很簡(jiǎn)單的,打印100以?xún)?nèi)能被2整除,不能被3整除
>>> b = {i:i%2==0 for i in range(10)} >>> b {0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}還有集合推導(dǎo)式:
>>> c = {i for i in [1,1,2,3,3,4,5,5,5,6,7,7,7,8]} >>> c {1, 2, 3, 4, 5, 6, 7, 8}那么有沒(méi)有字符串推導(dǎo)式,來(lái)驗(yàn)證下
>>> d = "I love python!" >>> d 'I love python!'看吧,不對(duì)吧,打印的是整個(gè)包含在字符串中的,所以不存在字符串推導(dǎo)式的說(shuō)法,那元組了?
>>> e = (i for i in range(10)) >>> e <generator object <genexpr> at 0x0000000003031360>看打印出來(lái)的信息是generator,這就是生成器,用小括號(hào)括起來(lái)的正是生成器,來(lái)看下效果
>>> next(e) 0 >>> next(e) 1 >>> next(e) 2 >>> next(e) 3 >>> next(e) 4 >>> next(e) 5>>> next(e)
6
>>> next(e)
7
用for循環(huán)吧剩下的打印出來(lái)
>>> for i in e:print(i)8 9生成器推導(dǎo)式如果作為函數(shù)的參數(shù),可以直接寫(xiě)推導(dǎo)式,而不用加小括號(hào)(這個(gè)很牛氣吧)。
>>> sum(i for i in range(100) if i%2) 2500?
轉(zhuǎn)載于:https://www.cnblogs.com/pinpin/p/9926366.html
總結(jié)
以上是生活随笔為你收集整理的python_魔法方法(六):迭代器和生成器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
                            
                        - 上一篇: 02全志r58平台Android4.4.
 - 下一篇: python 第三课 第一个pytho