python高级编程----迭代器与生成器

1.如何实现可迭代对象和迭代器对象?

某软件要求,从网络抓取各个城市气温信息,并一次显示:
北京 15–20
天津 17–22
…….
如果一次抓取所有城市天气在显示,显示第一个城市气温时,有时出现延时,并浪费存储空间,我们期望以’用时访问‘(惰性访问)策略,并且能把所有城市气温封装到一个对象里,可用for语句进行迭代。如果解决?

解决方法

#方法1
import requests
import json

def getWeather(city):
    #获取一个网页的响应数据
    re=requests.get('http://wthrcdn.etouch.cn/weather_mini?city='+city)
    #通过json解码得到字典
    d=json.loads(re.text)
    #这一步可以通过打印来查询子元素对象
    data=d['data']['forecast'][0]
    return '%s:%s,%s' % (city,data['low'],data['high'])

print( getWeather('上海'))
print(getWeather('广州'))

#方法2--通过迭代器与迭代对象完成
from collections import  Iterable, Iterator

#定义一个天气得迭代器
class WeatherIterator(Iterator):
    #定义构造器 cites为城市列表
    def __init__(self,cities):
        self.cities=cities
        #定义一个初始化得列表位置
        self.index=0

    #定义迭代器功能函数
    def getWeather(self,city):
        re = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=' + city)
        # 通过json解码得到字典
        d = json.loads(re.text)
        data = d['data']['forecast'][0]
        return '%s:%s,%s' % (city, data['low'], data['high'])

    #迭代器实现得方法--获取到迭代器中的元素,相当于next(Iterator)
    def __next__(self):
        if self.index==len(self.cities):
            raise StopIteration
        city=self.cities[self.index]
        self.index += 1
        return self.getWeather(city)


#定义一个天气的可迭代对象
class WeatherIterable(Iterable):
    def __init__(self,cities): #定义构造器
         self.cities=cities

    def __iter__(self):  #可迭代接口
         return WeatherIterator(self.cities)

#实例化一个可迭代对象
for x in WeatherIterable(['芜湖','北京','上海','广州','深圳']):
    print(x)

注意:
1.python3中常见的可迭代对象(iterable)有字符串,列表,字典,元组,集合等;
2.迭代器(iterator)是指能够用iter(obj)函数返回的对象(实例),并且通过next(it)函数获取可迭代对象的值;
3.相关的函数有:iter(iterable)—生成一个迭代器
next(iterator)—-获取下一个记录,或没有记录时,或出发StopIterator异常
4.for循环的工作原理:通过可迭代对象的iter方法得到一个迭代器,然后不停地调用next方法,知道出发StopIterator异常,则停止。


2.如何使用生成器函数实现可迭代对象?

实现一个可迭代对象的类,它能迭代出给定范围内所有素数 pn=PrimeNumbers(1,30)
for k in pn: print(k)
输出结果:2 3 5 7 11 13 17 19 23 29

解决办法

#生成器函数工作原理
def f():
    print('in f(),1')
    yield 1

    print('in f() ,2')
    yield 2

    print('in f(),3')
    yield 3

g=f()
# print(g is g.__iter__()) #说明给方法与迭代器类似
for x in g:
    # print(x)
    pass


#用生成器的方法实现
class PrimeNumbers:
    #定义构造器 
    def __init__(self,start,end):
        self.start=start
        self.end=end

    #功能函数--质数判断
    def isPrimeNum(self,k):
        if k<2:
            return False

        for i in range(2,k):
            if k%i==0:
                return False
        return True

    #定义生成器---该类的‘__iter__’方法实现生成器函数,每次yield返回一个素数
    def __iter__(self):
        for k in range(self.start,self.end):
            if self.isPrimeNum(k):
                yield k

for x in PrimeNumbers(1,100):
    print(x,end=' ')
print()

注意:
1.生成器是一个能够动态提供数据的对象(通过def–yield定义),生成器对象是可迭代对象,因此可以直接通过for语句取值;
2.生成器,即是可迭代对象,也是迭代器;因此,可以通过next(it)函数来取yiekd生成的数据


3.如何进行反向迭代以及如何实现反向迭代?

实现一个连续浮点数发生器FloatRange(类似range),根绝给定范围(start,end)和步长(step)产生一些列连续浮点数,如迭代FloatRange(3.0,4.0,0.2)可产生序列:

正向:3.0–3.2–3.4—3.6
反向: 4.0–3.8–3.6–3.4–3.2

解决办法

#利用迭代器解决正向与反向问题
class FloatRange:
    def __init__(self,start,end,step):
        self.start=start
        self.end = end
        self.step = step

    #正向迭代
    def __iter__(self):
        t=self.start
        while t<=self.end:
            yield t
            t +=self.step

    #反向迭代接口---实现反向迭代协议的__reversed__方法,它返回一个反向迭代器
    def __reversed__(self): 
        t=self.end
        while t>=self.start:
            yield t
            t -=self.step
for x in FloatRange(1.0,4.0,0.5):
    print(x,end=' ')
print()
for x in reversed(FloatRange(1.0,4.0,0.5)): 
    print(x,end=' ')

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

有某个文本文件,我们想读取其中某范围的内容,如100-300行之间的内容,python中文本文件时可迭代对象,我们是否可以使用类似列表切片的方式得到一个100-300行文件内容的生成器?

解决方法

#切片操作
f=open('filename')
#不可以直接对文本进行切片 f[100:300]
lines=f.readlines() #将文件一次性读入一个列表中,若文件很大,那可能导致内存不足
for line in f:
    print(line)

from itertools import islice
for line in islice(f,100,300):
    print(line)


#可迭代对象是被消耗的
l=list(range(10))
t=iter(l)
for i in islice(t,3,6):
    print(i,end=' ')
print('**********************')
for i in t:
    print(i,end=' ')

5.如何在一个for语句中迭代多个可迭代对象?

1.某班学生期末成绩,语文,数学,英语分别存储在3个列表中,同时迭代三个列表,计算每个学生的总分(并行)
2.某年纪有4个班,某次考试每班英语成绩分别储存在4个列表中,依次迭代诶个列表,统计全学年成绩高于90跟的人数(串行)

解决办法

#方法1--for遍历
from random import randint
chinese=[randint(40,100) for _ in range(20)]
math=[randint(40,100) for _ in range(20)]
english=[randint(40,100) for _ in range(20)]

#存在的问题,有些生成器不能通过索引的方式访问
for i in range(len(chinese)):
    my_sum=chinese[i]+math[i]+english[i]
    print(my_sum,end=' ')
print()

#方法2---zip函数,合并多个可迭代对象
total=[]
for c,m,e in  zip(chinese,math,english):
    total.append(c+m+e)

#方法3--itertools.chain函数 连接多个可迭代对象
e1=[randint(40,100) for _ in range(20)]
e2=[randint(40,100) for _ in range(28)]
e3=[randint(40,100) for _ in range(19)]
e4=[randint(40,100) for _ in range(31)]
from itertools import chain

count=0
for i in chain(e1,e2,e3,e4):
    if i >90:
        count +=1

你可能感兴趣的:(iterable,iterator)