Python 迭代器与生成器实例详解
Python迭代器与生成器实例详解
一、如何实现可迭代对象和迭代器对象
1.由可迭代对象得到迭代器对象
例如l就是可迭代对象,iter(l)是迭代器对象
In[1]:l=[1,2,3,4] In[2]:l.__iter__ Out[2]:In[3]:t=iter(l) In[4]:t.next() Out[4]:1 In[5]:t.next() Out[5]:2 In[6]:t.next() Out[6]:3 In[7]:t.next() Out[7]:4 In[8]:t.next() --------------------------------------------------------------------------- StopIterationTraceback(mostrecentcalllast) in () ---->1t.next() StopIteration: forxinl: printx for循环的工作流程,就是先有iter(l)得到一个t,然后不停的调用t.nex(),到最后捕获到StopIteration,就结束迭代
#下面这种直接调用函数的方法如果数据量大的时候会对网络IO要求比较高,可以采用迭代器的方法
defgetWeather(city): r=requests.get(u'http://wthrcdn.etouch.cn/weather_mini?city='+city) data=r.json()['data']['forecast'][0] return'%s:%s,%s'%(city,data['low'],data['high']) printgetWeather(u'北京') 返回值:
北京:低温13℃,高温28℃
实现一个迭代器对象WeatherIterator,next方法每次返回一个城市气温
实现一个可迭代对象WeatherIterable,iter方法返回一个迭代器对象
#-*-coding:utf-8-*- importrequests fromcollectionsimportIterable,Iterator classWeatherIterator(Iterator): def__init__(self,cities): self.cities=cities self.index=0 defgetWeather(self,city): r=requests.get(u'http://wthrcdn.etouch.cn/weather_mini?city='+city) data=r.json()['data']['forecast'][0] return'%s:%s,%s'%(city,data['low'],data['high']) defnext(self): ifself.index==len(self.cities): raiseStopIteration city=self.cities[self.index] self.index+=1 returnself.getWeather(city) classWeatherIterable(Iterable): def__init__(self,cities): self.cities=cities def__iter__(self): returnWeatherIterator(self.cities) forxinWeatherIterable([u'北京',u'上海',u'广州',u'深圳']): printx.encode('utf-8') 输出: 北京:低温13℃,高温28℃ 上海:低温14℃,高温22℃ 广州:低温17℃,高温23℃ 深圳:低温18℃,高温24℃
二、使用生成器函数实现可迭代对象
1.实现一个可迭代对象的类,它能迭代出给定范围内所有素数
素数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数的数称为素数。
一个带有yield的函数就是一个generator,它和普通函数不同,生成一个generator看起来像函数调用,但不会执行任何函数代码,直到对其调用next()(在for循环中会自动调用next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个yield语句就会中断,并返回一个迭代值,下次执行时从yield的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被yield中断了数次,每次中断都会通过yield返回当前的迭代值。
classPrimeNumbers: def__init__(self,start,end): self.start=start self.end=end defisPrimeNum(self,k): ifk<2: returnFalse foriinxrange(2,k): ifk%i==0: returnFalse returnTrue def__iter__(self): forkinxrange(self.start,self.end+1): ifself.isPrimeNum(k): yieldk forxinPrimeNumbers(1,10): printx 输出: 2 3 5 7
三、实现反向迭代
1.反向进行迭代
例如:实现一个浮点数发生器FloatRange(和xrange类似),根据给定范围(start,end)和步径值(step)产生一系列连续浮点数,如迭代FloatRange(3.0,4.0,0.2)可产生序列:
正向:3.0->3.2->3.4->3.6->3.8->4.0
反向:4.0->3.8->3.6->3.4->3.2->3.0
classFloatRange: def__init__(self,start,end,step=0.1): self.start=start self.end=end self.step=step def__iter__(self): t=self.start whileround(t,14)<=round(self.end,14): yieldt t=t+self.step def__reversed__(self): t=self.end whileround(t,14)>=round(self.start,14): yieldt t=t-self.step forxinreversed(FloatRange(3.0,4.0,0.2)): printx 输出: 4.0 3.8 3.6 3.4 3.2 3.0 forxinFloatRange(3.0,4.0,0.2):
printx
输出:
3.0
3.2
3.4
3.6
3.8
4.0
上面代码采用round函数是因为浮点数比较会有精度问题,所以需要进行四舍五入
2.对迭代器进行切片操作
例如:有某个文本文件,想读取其中某范围的内容,如100-300行之间的内容,python中文本文件是可迭代对象,是否可以使用类似列表切片的方式得到一个100-300行文件内容的生成器
使用标准库中的itertools.islice,它能返回一个迭代对象切片的生成器
f=open('/var/log/dmesg') fromitertoolsimportislice #对文件内容100到300行之间进行切片,返回的是个生成器对象,默认歩径是1 islice(f,100,300) #前500行内容 islice(f,500) #100行到末尾结束内容 islice(f,100,None) ps:每次使用islice要重新申请对象,它会消耗原来的迭代对象
四、迭代多个对象
1.在一个for语句中迭代多个可迭代对象
1、某班学生考试成绩语文、数学、英语分别存储在3个列表中,同时迭代三个列表,计算三个学生的总分(并行)
2、某年级四个班,某次考试每班英语成绩分别存储在4个列表中,依次迭代每个列表,统计全学年英语成绩高于90分人数(串行)
解决方案:
并行:使用内置函数zip,它能将多个可迭代对象合并,每次迭代返回一个元组
fromrandomimportrandint chinese=[randint(60,100)for_inxrange(40)] math=[randint(60,100)for_inxrange(40)] english=[randint(60,100)for_inxrange(40)] total=[] forc,m,einzip(chinese,math,english): total.append(c+m+e) printtotal 输出: [204,227,238,201,227,205,251,274,210,242,220,239,237,207,230,267,263,240,247,249,255,268,209,270,259,251,245,262,234,221,236,250,251,249,242,255,232,272,237,253]
串行:使用标准库中的itertools.chain,它能将多个可迭代对象连接
fromrandomimportrandint fromitertoolsimportchain class1=[randint(60,100)for_inxrange(40)] class2=[randint(60,100)for_inxrange(42)] class3=[randint(60,100)for_inxrange(39)] class4=[randint(60,100)for_inxrange(43)] count=0 forsinchain(class1,class2,class3,class4): ifs>90: count=count+1 printcount 输出: 38
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!