1.如何實(shí)現(xiàn)可迭代對(duì)象和迭代器對(duì)象如果想從網(wǎng)絡(luò)上抓取數(shù)據(jù)存入字典,,然后再對(duì)字典進(jìn)行迭代顯示,,由于網(wǎng)絡(luò)I/O操作的時(shí)間相對(duì)較長(zhǎng),這樣就會(huì)造成用戶的長(zhǎng)時(shí)間等待,,我們希望能一次抓取就顯示一次,,于是迭代器對(duì)象出現(xiàn)了。 在 for 循環(huán)的時(shí)候 in 后面跟的是一個(gè)可迭代對(duì)象,,在循環(huán)的過程中自動(dòng)調(diào)用 iter() 將可迭代對(duì)象傳入其中,,返回一個(gè)迭代器對(duì)象 比如我們常見的列表和字符串都是可迭代對(duì)象,為什么呢? 這涉及到了 Python 的魔法方法的問題,,python一切皆對(duì)象,,而魔法方法就是好像是python對(duì)象的一個(gè)插件,有什么樣子的魔法方法,,python 對(duì)象就會(huì)在關(guān)鍵時(shí)刻顯示某種特性(仿佛科幻小說中主人公體內(nèi)某種隱藏的力量被激活),。迭代對(duì)象有一個(gè)魔法方法 __iter__ ,如果沒有這個(gè)方法,那么python 還會(huì)退而求其次,,去尋找__getitem__ 這個(gè)代表他是一個(gè)序列的方法,,也是可迭代的。 迭代器對(duì)象只有一個(gè)方法就是 next(),,每調(diào)用一次就會(huì)迭代一次,,知道全部迭代完畢拋出異常,這其實(shí)也是for 循環(huán)的工作機(jī)制(這同時(shí)也說明了一個(gè)問題:迭代器內(nèi)部持有一個(gè)狀態(tài),,該狀態(tài)用于記錄當(dāng)前迭代所在的位置,,以方便下次迭代的時(shí)候獲取正確的元素)。
結(jié)果:
實(shí)例: 實(shí)現(xiàn)一個(gè)迭代器對(duì)象,,有next 方法每次返回一個(gè)值 實(shí)現(xiàn)一個(gè)可迭代對(duì)象 __iter__ 方法返回上面的那個(gè)迭代器對(duì)象
實(shí)際上就是創(chuàng)建一個(gè)可迭代對(duì)象的類,,實(shí)例化以后成為一個(gè)可迭代對(duì)象,然后一旦在循環(huán)中調(diào)用這個(gè)可迭代對(duì)象就能自動(dòng)調(diào)用__init__ ,然后實(shí)例化迭代器對(duì)象的類,,這個(gè)類的實(shí)例會(huì)在迭代中不斷調(diào)用next方法。 代碼如下: from collections import Iterable,Iterator class WeatherIterator(Iterator): def __init__(self,cities): def getWeather(self,city): r = requests.get(u"http://wthrcdn./weather_mini?city=" + city) data = r.json()['data']['forecast'][0] return '%s: %s , %s' % (city, data['low'], data['high']) if self.index == len(self.cities): city = self.cities[self.index] return self.getWeather(city) class WeatherIterable(Iterable): def __init__(self,cities): return WeatherIterator(self.cities) for x in WeatherIterable([u"北京",u"上海",u"廣州",u"長(zhǎng)春"]):
2.如何使用生成器函數(shù)實(shí)現(xiàn)可迭代對(duì)象那么什么是生成器,? 生成器對(duì)象其實(shí)是一種特殊的可迭代對(duì)象,,他自己調(diào)用__iter__ 方法返回的是他自身,因此他既是一個(gè)可迭代對(duì)象,,也是一個(gè)迭代器對(duì)象,,而且它不需要再像上面的類一樣寫__iter__() 和__next__() 方法了,只需要一個(gè)yiled關(guān)鍵字(當(dāng)然你可以重寫__iter__ 來實(shí)現(xiàn)自己的功能),。 (說人話就是這個(gè)生成器的對(duì)象在每一次迭代的時(shí)候都會(huì)被yiled卡住并返回,,下一次再迭代就會(huì)接著上次執(zhí)行,是不是很優(yōu)雅,?) 舉一個(gè)簡(jiǎn)單的生成器的例子:
結(jié)果:
實(shí)例: 找出指定范圍內(nèi)的所有素?cái)?shù) def __init__(self,start,end): for k in xrange(self.start,self.end+1): for x in PrimeNumbers(1,100):
3.如何進(jìn)行反向迭代以及如何實(shí)現(xiàn)反向迭代列表的反向迭代(1)使用列表的反轉(zhuǎn)操作
但這種情況會(huì)改變?cè)斜?/p> (2)使用切片且步進(jìn)為-1
但這樣會(huì)生成一個(gè)新的列表 (3)列表反向迭代器
這種情況和iter()剛好是相反的,,在迭代的時(shí)候會(huì)自動(dòng)調(diào)用 __reversed__ 對(duì)象。 實(shí)例: 寫一個(gè)浮點(diǎn)數(shù)生成器,,既可以正向迭代又可以反向迭代 def __init__(self,start,end,step): for x in FloatRange(1.0,3.0,0.5): print "===============cut-off rule=====================" for x in reversed(FloatRange(1.0,3.0,0.5)):
4.如何對(duì)迭代器做切片操作我們知道文本文件本身也是一個(gè)可迭代對(duì)象,,每次迭代返回的是文本文件的一行,那么我們思考一個(gè)問題,,我們能不能像對(duì)列表切片一樣對(duì)文本文件切片得到一個(gè)迭代器(生成器),,這樣比如我們想迭代的是100行帶300行之間的內(nèi)容就能直接迭代了。 簡(jiǎn)單回顧文件迭代由于文件對(duì)象沒有__getitem__ 這個(gè)方法,于是沒有和列表一樣的迭代操作,,那我們就可以先把文件的內(nèi)容放到一個(gè)列表里面,,然后再進(jìn)行切片,如下:
但是這樣有一個(gè)問題,,readlines 會(huì)把文件的所有內(nèi)容都先加載到內(nèi)存里面,,但是如果文件非常大,比如有幾個(gè)G大小,,那么就會(huì)遇到內(nèi)存不足的問題,,于是我們只能選擇使用
注意:如果文件指針此時(shí)已經(jīng)在文件的末尾,你是循環(huán)不出內(nèi)容的,,我們還需要將使用 f.seek(0),,將文件指針還原回去 因此我們迫切的需要將文件變成一個(gè)迭代器。 from itertools import islice for i in islice(f,100,300):
如果是想得到前100行的迭代器 from itertools import islice
如果想得到從100行開始到最后的迭代器 from itertools import islice for i in islice(f,100,None):
注意: islice() 雖然看上去是從100開始的,,但是前99行實(shí)際上也迭代了,,因此下一次使用的時(shí)候注意還原。 5.如何在一個(gè)for 語句中迭代多個(gè)可迭代對(duì)象1.并行迭代比如 語數(shù)外三科成績(jī)分別存儲(chǔ)在3個(gè)列表中,,我們現(xiàn)在需要同時(shí)迭代三個(gè)列表取出三個(gè)成績(jī),,并計(jì)算總成績(jī) 最簡(jiǎn)單的我們可以使用索引的方式 from random import randint chinese = [randint(60,100) for i in xrange(40)] math = [randint(60,100) for i in xrange(40)] english = [randint(60,100) for i in xrange(40)] for x in xrange(len(math)): print chinese[x]+math[x]+english[x]
但是這個(gè)方法有局限性,因?yàn)椴⒉皇撬械目傻鷮?duì)象都支持索引的方法訪問其中的元素 高階推薦:zip() zip() 中能傳入多個(gè)可迭代對(duì)象并將其逐項(xiàng)合并成一個(gè)元組列表,,然后我們就能使用元組拆包的方式進(jìn)行迭代 from random import randint chinese = [randint(60,100) for i in xrange(40)] math = [randint(60,100) for i in xrange(40)] english = [randint(60,100) for i in xrange(40)] for c,m,e in zip(chinese,math,english):
2.串行比如每個(gè)班的英語成績(jī)放在一個(gè)列表中,,現(xiàn)在想迭代全年級(jí)的英語成績(jī),找出分?jǐn)?shù)高于90分的人數(shù) 使用 itertools 的 chain 可以多個(gè)可迭代對(duì)象進(jìn)行串行連接 from random import randint from itertools import chain e1 = [randint(60,100) for i in xrange(40)] e2 = [randint(60,100) for i in xrange(40)] e3 = [randint(60,100) for i in xrange(40)] e4 = [randint(60,100) for i in xrange(40)] for x in chain(e1,e2,e3,e4):
|