如何实现可迭代对象和迭代器对象
实际案列
某网络要求抓取各个城市气温信息,并依次显示:
北京:15~20
天津:17~22
长春:12~18
...
如果一次抓取所有城市气温在显示,显示第一个城市气温时,有很高的延时,并且浪费存储空间,我们期望以""用时访问"策略,并且把所有城市气温封装到一个对象里,可以用for
语句迭代,如何解决?
from collections import Iterable Iterator
l=[1,2,3,4,5]
for i in l:
print(i)
isintances(l,Iterable)
true
issubclass(list,Iterable)
iter(l)
#迭代器对象是由可迭代对象生成的,iter其实是实现了l.__iter__方法
#next对迭代器进行迭代,没迭代一次就出现一个元素
iter(l)~---it=====(next) iter~~it~~.(StopIteration
it=iter(l)
it__iter__
如何使用生成器函数实现可迭代对象?
实际案例
实现一个可迭代对象的类,他能迭代出给定范围内所有素数:
pn=PrimeNumbers(1,30)
for k in pn:
print k,
输出结果:
2,3,5,7,11,13,17,19,23,29
解决方案:
将该类的__iter__
方法实现生成器函数,每次yield返回一个素数
from collections import Iterable Iterabor
import requests
class WeatherIterator(Iterator):
def__init__(self,caties):
self.caties=caties
self.index=0
def __next__(self):
if self.index == len(self.caties):
raise StopIteration
city = self.cities[self.iindex]
self.index+=1
reurn self.get_weather(city)
def get_waather(self,city):
url='http://wthrcdn,etouch.cn/weather_mini?city=='+city
r=requests.get(url)
data=r.json()['data']['forecast'][0]
return city,data['high'],data['low']
class WeatherIterable(Iterable):
def __init__(self,cities):
self.cities=cities
def __iter__(self):
return WeatherIterator(self.cities):
def show(w):
for x in w:
print(x)
生成器函数就是包含了yield
语句的函数
def f():
yield('in f 1')
yield1
yield('in f 2')
yield2
yield('in f 3')
yield3
f()
(g,Iterator)
(g,Iterable)
class XXX_iTERABLE(Iterable):
def__def__iter__():
class PrimeNumbers(Iterable):
def __init__(self):
pass
def __iter__(self):
for k in range(self.a,self.b+1)
if self.is_prime(K):
yield k
def is_prime(self,k)
#if k <2:
# return False
#[2,k-1]
#for x in range (2,k)
# if k % x ==0:
# return False
return False if x<2 else all(map(lambda x:k % x,range(2,k)))
return True
pn = PrimeNumbers(1,30)
for n in pn:
print(n)
如何进行反向迭代以及如何实现反向迭代?
研讨问题:
如何进行反向迭代以及如何进行反向迭代?
实际案例:
实现一个连续浮点数发生器FloatRange
(和range类似)根据给定范围(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
解决方案:
实现反向迭代协议的__reversed__
方法,它返回一个反向迭代器。
from decimal import Decimal
class FloatRange():
def __init__(self,a,b,,step):
self.a=Decimal(str(a))
self.b=Decimal(str(b))
self.step=Decimal(str(step))
def __iter__(self):
t=self.a
while t<=self.b
yield float(t)
t+=self.step
def __reversed__(self):
t=self.b
while t>=self.a:
yield float(t)
t-=self.step
fr = FloatRange(3.0 4.0,0.2)
for x in fr:
print(x)
print('-'*20)
for x in reversed(fr):
print(x)
from decimal import Decimal
Decimal('0.2')
from functools import reduce
reduce(Decimal.__add__,[Decimal('0.2')]*5)
如何对迭代器做切片操作?
实际案例:
有某个文本文件,我们想读取其中某个范围的内容如100~300行之间的内容,python中文件是可迭代对象,我们是否可以使用列表切片的方式得到一个100~300行文件内容的生成器?
f=open('/var/log/dpkg')
for line in f[100:300]: #可以吗?
...
解决方案:
使用itertools.islice
,它能返回一个迭代对象切片的生成器.
f=open('/var//log/dpkg.log.1')
f.__
for line in islice(f,100~1,300)
print(x)
def my_ilice(iterable,startend,,step=1)
for i,x in enumerate(Iterable ,seep=1)
tmp=0
for i in enumerate(iterable):
if i>=end:
break
if i>=start:
if tmp==0
tmp=step
yield x
tmp-=1
print(list(my_islice(range(100,150),10,20,3)))
from itertools import islice
print(list(islice(range(100,150),10,20,3)))
如何在一个for语句中迭代多个可迭代对象?
研讨问题:
如何在一个for语句中迭代多个可迭代对象
实际案例:
1.(并行)某班学生考试成绩,语文,数学,英语分别存储在3个列表中,同时迭代三个列表,计算每个学生的总分.
2.(串行)某年级有4个班,某次考试每班英语成绩分别存储在4个列表中,依次迭代每个列表,统计全年成绩高于90分人数.
解决方案:
1.并行:使用内置函数zip
,它能将多个可迭代对象合并,每次迭代返回一个元组.
from random import randint
chinese = [randint(60.100) for _ in range(20)]
math = [randint(60,100) for _ in range(20)]
english = [randint(60,100) for _ in range(20)]
t=[]
for s1,s2,s3 in zip(chinese,math,english)
t.append(s1+s2+s3)
[sum(s) for s in zip(chinese,math,english)]
list(map()sum,zip(chinese,math,english))
list(map(lambda s1,s2,s3:s1+s2+s3,chinese,math,english))
map(lambda *args:args,chinese,math,english)
map(zip(chinese,math,english))
list(map(None,chinese,math,english))
2.串行:使用标准库中的itertools.chain,它能将多个迭代对象连接.
from itertools import chain
for x in chain([1,2,3],[4,5,6,7],[8,9]):
print(x)
s='abc;123|xyz;678|fweuow \ t7zka'
list(map(lambda ss:ss.split('|'),s.split(';')))
(list(chain[*[list(map(lambda ss:ss.split('|'),s.split(';')))]])
from functools import reduce
list(reduce(lambda it_s,sep:chain(*map(lambda ss:ss.split(sep), it_s)),';|\t',[s]))