日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Python 實(shí)用編程技巧(迭代篇)

 dinghj 2019-04-17

1.如何實(shí)現(xiàn)可迭代對象和迭代器對象

如果想從網(wǎng)絡(luò)上抓取數(shù)據(jù)存入字典,然后再對字典進(jìn)行迭代顯示,由于網(wǎng)絡(luò)I/O操作的時間相對較長,這樣就會造成用戶的長時間等待,我們希望能一次抓取就顯示一次,于是迭代器對象出現(xiàn)了。
在 for 循環(huán)的時候 in 后面跟的是一個可迭代對象,在循環(huán)的過程中自動調(diào)用 iter() 將可迭代對象傳入其中,返回一個迭代器對象

比如我們常見的列表和字符串都是可迭代對象,為什么呢?

這涉及到了 Python 的魔法方法的問題,python一切皆對象,而魔法方法就是好像是python對象的一個插件,有什么樣子的魔法方法,python 對象就會在關(guān)鍵時刻顯示某種特性(仿佛科幻小說中主人公體內(nèi)某種隱藏的力量被激活)。迭代對象有一個魔法方法 __iter__,如果沒有這個方法,那么python 還會退而求其次,去尋找__getitem__ 這個代表他是一個序列的方法,也是可迭代的。

迭代器對象只有一個方法就是 next(),每調(diào)用一次就會迭代一次,知道全部迭代完畢拋出異常,這其實(shí)也是for 循環(huán)的工作機(jī)制(這同時也說明了一個問題:迭代器內(nèi)部持有一個狀態(tài),該狀態(tài)用于記錄當(dāng)前迭代所在的位置,以方便下次迭代的時候獲取正確的元素)。


  1. l = [1,2,3,4,5,6]
  2. t = iter(l)
  3. print t.next()
  4. print t.next()
  5. print t.next()

結(jié)果:

  1. 1
  2. 2
  3. 3

實(shí)例:

  1. 實(shí)現(xiàn)一個迭代器對象,有next 方法每次返回一個值

  2. 實(shí)現(xiàn)一個可迭代對象 __iter__ 方法返回上面的那個迭代器對象

實(shí)際上就是創(chuàng)建一個可迭代對象的類,實(shí)例化以后成為一個可迭代對象,然后一旦在循環(huán)中調(diào)用這個可迭代對象就能自動調(diào)用__init__,然后實(shí)例化迭代器對象的類,這個類的實(shí)例會在迭代中不斷調(diào)用next方法。

代碼如下:

  1. import requests
  2. from collections import Iterable,Iterator
  3. class WeatherIterator(Iterator):
  4. def __init__(self,cities):
  5. self.cities = cities
  6. self.index = 0
  7. def getWeather(self,city):
  8. r = requests.get(u"http://wthrcdn./weather_mini?city=" + city)
  9. data = r.json()['data']['forecast'][0]
  10. return '%s: %s , %s' % (city, data['low'], data['high'])
  11. def next(self):
  12. if self.index == len(self.cities):
  13. raise StopIteration
  14. city = self.cities[self.index]
  15. self.index += 1
  16. return self.getWeather(city)
  17. class WeatherIterable(Iterable):
  18. def __init__(self,cities):
  19. self.cities = cities
  20. def __iter__(self):
  21. return WeatherIterator(self.cities)
  22. for x in WeatherIterable([u"北京",u"上海",u"廣州",u"長春"]):
  23. print x

2.如何使用生成器函數(shù)實(shí)現(xiàn)可迭代對象

那么什么是生成器?

生成器對象其實(shí)是一種特殊的可迭代對象,他自己調(diào)用__iter__方法返回的是他自身,因此他既是一個可迭代對象,也是一個迭代器對象,而且它不需要再像上面的類一樣寫__iter__()__next__()方法了,只需要一個yiled關(guān)鍵字(當(dāng)然你可以重寫__iter__來實(shí)現(xiàn)自己的功能)。 (說人話就是這個生成器的對象在每一次迭代的時候都會被yiled卡住并返回,下一次再迭代就會接著上次執(zhí)行,是不是很優(yōu)雅?)

舉一個簡單的生成器的例子:

  1. def f():
  2. print 'first'
  3. yield 1
  4. print 'second'
  5. yield 2
  6. print 'third'
  7. yield 3
  8. g = f()
  9. for x in g:
  10. print x

結(jié)果:

  1. first
  2. 1
  3. second
  4. 2
  5. third
  6. 3

實(shí)例:

找出指定范圍內(nèi)的所有素數(shù)

  1. class PrimeNumbers:
  2. def __init__(self,start,end):
  3. self.start = start
  4. self.end = end
  5. def isPrimeNum(self,k):
  6. if k<2:
  7. return False
  8. for x in xrange(2,k):
  9. if k % x == 0:
  10. return False
  11. return True
  12. def __iter__(self):
  13. for k in xrange(self.start,self.end+1):
  14. if self.isPrimeNum(k):
  15. yield k
  16. for x in PrimeNumbers(1,100):
  17. print x

3.如何進(jìn)行反向迭代以及如何實(shí)現(xiàn)反向迭代

列表的反向迭代

(1)使用列表的反轉(zhuǎn)操作

  1. l = [1,2,3,4,5]
  2. x = l.reverse()

但這種情況會改變原列表

(2)使用切片且步進(jìn)為-1

  1. l = [1,2,3,4,5]
  2. x = l[::-1]

但這樣會生成一個新的列表

(3)列表反向迭代器

  1. l = [1,2,3,4,5]
  2. for x in reversed(l):
  3. print x

這種情況和iter()剛好是相反的,在迭代的時候會自動調(diào)用 __reversed__對象。

實(shí)例:

寫一個浮點(diǎn)數(shù)生成器,既可以正向迭代又可以反向迭代

  1. class FloatRange:
  2. def __init__(self,start,end,step):
  3. self.start = start
  4. self.end = end
  5. self.step = step
  6. def __iter__(self):
  7. t = self.start
  8. while t <= self.end:
  9. yield t
  10. t +=self.step
  11. def __reversed__(self):
  12. t = self.end
  13. while t >= self.start:
  14. yield t
  15. t -= self.step
  16. for x in FloatRange(1.0,3.0,0.5):
  17. print x
  18. print "===============cut-off rule====================="
  19. for x in reversed(FloatRange(1.0,3.0,0.5)):
  20. print x

4.如何對迭代器做切片操作

我們知道文本文件本身也是一個可迭代對象,每次迭代返回的是文本文件的一行,那么我們思考一個問題,我們能不能像對列表切片一樣對文本文件切片得到一個迭代器(生成器),這樣比如我們想迭代的是100行帶300行之間的內(nèi)容就能直接迭代了。

簡單回顧文件迭代

由于文件對象沒有__getitem__這個方法,于是沒有和列表一樣的迭代操作,那我們就可以先把文件的內(nèi)容放到一個列表里面,然后再進(jìn)行切片,如下:

  1. f = open('./LICENCE')
  2. lines = f.readlines()
  3. for x in lines[100:300]:
  4. print x

但是這樣有一個問題,readlines 會把文件的所有內(nèi)容都先加載到內(nèi)存里面,但是如果文件非常大,比如有幾個G大小,那么就會遇到內(nèi)存不足的問題,于是我們只能選擇使用

  1. for line in f:
  2. print line,

注意:如果文件指針此時已經(jīng)在文件的末尾,你是循環(huán)不出內(nèi)容的,我們還需要將使用 f.seek(0),將文件指針還原回去

因此我們迫切的需要將文件變成一個迭代器。

  1. from itertools import islice
  2. f = open('./LICENCE')
  3. for i in islice(f,100,300):
  4. print i

如果是想得到前100行的迭代器

  1. from itertools import islice
  2. f = open('./LICENCE')
  3. for i in islice(f,100):
  4. print i

如果想得到從100行開始到最后的迭代器

  1. from itertools import islice
  2. f = open('./LICENCE')
  3. for i in islice(f,100,None):
  4. print i

注意: islice() 雖然看上去是從100開始的,但是前99行實(shí)際上也迭代了,因此下一次使用的時候注意還原。

5.如何在一個for 語句中迭代多個可迭代對象

1.并行迭代

比如 語數(shù)外三科成績分別存儲在3個列表中,我們現(xiàn)在需要同時迭代三個列表取出三個成績,并計算總成績

最簡單的我們可以使用索引的方式

  1. from random import randint
  2. chinese = [randint(60,100) for i in xrange(40)]
  3. math = [randint(60,100) for i in xrange(40)]
  4. english = [randint(60,100) for i in xrange(40)]
  5. for x in xrange(len(math)):
  6. print chinese[x]+math[x]+english[x]

但是這個方法有局限性,因為并不是所有的可迭代對象都支持索引的方法訪問其中的元素

高階推薦:zip()

zip() 中能傳入多個可迭代對象并將其逐項合并成一個元組列表,然后我們就能使用元組拆包的方式進(jìn)行迭代

  1. from random import randint
  2. chinese = [randint(60,100) for i in xrange(40)]
  3. math = [randint(60,100) for i in xrange(40)]
  4. english = [randint(60,100) for i in xrange(40)]
  5. grade = []
  6. for c,m,e in zip(chinese,math,english):
  7. grade.append(c+m+e)
  8. print grade

2.串行

比如每個班的英語成績放在一個列表中,現(xiàn)在想迭代全年級的英語成績,找出分?jǐn)?shù)高于90分的人數(shù)

使用 itertools 的 chain 可以多個可迭代對象進(jìn)行串行連接

  1. from random import randint
  2. from itertools import chain
  3. e1 = [randint(60,100) for i in xrange(40)]
  4. e2 = [randint(60,100) for i in xrange(40)]
  5. e3 = [randint(60,100) for i in xrange(40)]
  6. e4 = [randint(60,100) for i in xrange(40)]
  7. count = 0
  8. for x in chain(e1,e2,e3,e4):
  9. if x > 90:
  10. count += 1

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多