# python 高级应用 第三章

3-1 ,2如何实现可迭代对象和迭代器对象

实际案列:某软件要求,从网络抓取各个城市的信息,并以此显示:
北京:15-20

天津:17-22

长春:12-18

如果一次抓取所有城市天气再显示,显示第一个城市气温时,有很高的延迟,并且浪费存储空间,我们期望其“用时访问”的策略,并且能够把所有城市气温封装到一个对象里,可以使用for来进行迭代。

首先介绍可迭代对象和迭代器:

可迭代对象可以得到跌倒器,for循环的工作原理,for循环首先调用可迭代对象的__ iter__ 方法,然后获得一个迭代器在调用迭代器的next方法,不停地输出对象。

l=[1,2,3,4,5]
s='abcde'
for x in l : print x ## in 后面的对象必须保证是可得带对象,

t=iter(l)
t.next()#每调用一次打印出一个元素

解决方案:

step1:实现一个迭代器对象WeatherIterator , next 方法每次返回一个城市气温。

step2:实现一个可迭代对象WeatherIterator, next 方法返回一个可迭代对象。

import requests
def getWeather(city):
    r=requests.get(u'http://wthrcdn.etouch.cn/weather_mini?city='+city)
    data=r.json()['data']['forecast'][0]
    return '%$: %$, %$' %(city,data['low'],data['high'])

print(getWeather('北京'))
print(getWeather('长春'))

from collections import Iterable,Iterator
class weatherIterator(Iterator):
    def __init__(self,cities):
        self.cities= cities
        self.index=0
    def getWeather(self,city):
        r=requests.get(u'http://wthrcdn.etouch.cn/weather_mini?            city='+city)
        data=r.json()['data']['forecast'][0]
        return '%$: %$, %$' %(city,data['low'],data['high'])
    def next(self):
        if self.index==len(self.cities):
            raise.StopIteration
        city=self.cities[self.index]
        self.index +=
        return self.getWeather(city)
    
 class WeatherIterable(Iterable):
    def __init__(self.cities):
        self.cities=cities
    def __init__(self):
        return WeatherIterator(self.cities)
 for x in WeatherIterable([u"北京,上海,广州,长春"]):
    print(x)
    
    

3-3 如何使用生成器来实现可迭代对象

实际案例:实现一个可迭代对象的类,它能够迭代出给定范围内的所有的素数:

pn=PrimeNumber(1,30)
for k in pn:
    print K
# 输出结果:2,3,5,7,11,13,17,19

解决方案:将该类的__ iter__ 方法实现成生成器函数,每次yield返回一个素数

# 首先我们来看下生成器的工作原理
#!/python2
def f():
    print 'in f(), 1'
    yield 1
    
    print 'in f(), 2'
    yield 2
    
    print 'in f(), 3'
    yield 3
    
 g=f() #没有东西打印出来
print(g.next()) #打印出‘in f(), 1

#生成器对象也是一个可迭代对象,可迭代对象也就说它可以放在in后面,
for x in g:
    print(x)
    
# 结果就进行了迭代,也就是说g实现了g.__iter__ 这个方法 就是它自身
# 验证:
print (g.__iter__() is g)

综上所述,生成器对象和迭代器对象的行为完全一致,把可迭代对象的__ iter()__方法变为生成器函数

#!/usr/bin/python2
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 xrange(2,k):
            if k % i==0:
                return False
        return True
    
    def __iter__(self):
        for k in xrange(self.start, self.end +1):
            if self.isPrimeNum(k):
                yield(k)
for x in PrimeNumbers(1,100):
    print(x)
        
        
    

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

实际案例:实现一个连续浮点数发生器FloatRange (和xrange )类似,根据给定的范围(start, end)和进步值(step)来生成一系列连续的浮点数,如迭代FlostRange (3.0, 4.0, 0.2)可产生序列:

正向:3.0->3.2->3.4->.....->4.0

反向:4.0->3.8->3.6->......->3.0

正向就是实现一个可迭代对象,就是实现它的__ iter__ 方法,reversed同样也需要支持__ reverse__ 方法

l=[1,2,3,4,5]
l.reverse() #改变了原列表,l为[5,4,3,2,1]
# 在不允许改变原列表的情况下这个方法就用不了
1[::-1] #使用切片的方法,虽然并没有改变原列表但是生成了一个和原列表同样大小的一个列表,这样就很占内存

# 推荐使用函数reversed(),其原理和迭代器是一样的,只不过迭代器iter()返回的正向的值,而reversed()返回的是反向的迭代对象
for x in reversed(l):
    print(x)

具体实现

#!/usr/bin/python2
class FloatRange:
    def __init__(self, start, end, step=0.1):
        self.start=start
        self.end=end
        self.step=step
        
    def __iter__(self): #正向迭代
        t = self.start
        while t <= self.end:
            yield t
            t += self.step
            
    def __reversed__(self): #反向迭代
        t = self.end
        while t >= self.start:
            yield t
            t -= self.step
for x in FloatRange(1.0, 4.0, 0.2): #此时调用的是FloatRange的内部函数__iter__
    print(x)
# 如果是反向迭代的话:
for x in reversed(FloatRange(1.0, 4.0, 0.2)): #此时调用的是FloatRange内部的__reversed__ 函数
    print(x)

3.4 如何对得带器进行切片操作

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

# 简单的实现方法
f=open('English.txt')
lines=f.readlines()
lines[2:4] #这就可以使用列表切片,但是存在的问题是,readlines会把整个文档读取,当文件很小的时候,还好,如果文件很大,不仅会占用很多的内存,同时也很费时间。

#下面使用迭代的方法
for line in f:
    print(line) #结果没有输出是因为刚才的readlines将文件的指针定位到文件的最后。
f.seek(0) #将文件指针定位到文件的开头
for line in f:
    print(line) #现在就可以逐行返回    

解决方案:使用标准库中的itertools.slice ,它能够返回一个迭代对象切片的生成器。

from itertools import islice
help(islice)
#islice(iterable, [start],stop,[step]) #islice的三个参数
f=open('English.txt')
for i in islice(f, 7, 16):
    print(i)
islice(f,10) #传入得到是前10行的内容
islice(f,10,None) #传入第10行到最后一行
## islice不支持负的参数,因为我们在没有读完整个文件之前,是不知道文件有多少行。

islice 函数的解析:

l=range(20) #生成1到20范围内的列表
t=iter(l) #将l转换成一个迭代器
for x in islice(t,5,10):
    print(x)
#原理解释: t是整个都被迭代过的,但是前面的1到5的数字不满足要求,所有被过滤掉了,直到遇到在5到10行的值才被返回
# 如果接下来继续迭代对象的话就是从10开始,因为之前的代码已经迭代到10了
for x in t:
    print(x)

3-6 如何在一个for语句中迭代多个可迭代对象

实际案例:

1.某班学生期末考试成绩,语文,数学,英语分别存储在3个列表中,同时迭代三个列表,计算每个学生的总分。(并行)

# 简单的实现方法:
from random import randint
chinese=[randint(60,100) for _ in xrange(40)]
math=[randint(60,100) for _ in xrange(40)]
English=[randint(60,100) for _ in xrange(40)]
for i in xrange(len(math)):
    sumUp=chinese[i] + math[i] + English[i]
    print(sumUp)

解决方案:

并行->并行:使用内置函数zip, 它可以将多个迭代对象合并,每次迭代返回一个元组。(zip函数在连接的时候,如果长度不一致的话,就会取较短的一组元素的长度)

# 使用zip函数来实现
from random import randint
chinese=[randint(60,100) for _ in xrange(40)]
math=[randint(60,100) for _ in xrange(40)]
English=[randint(60,100) for _ in xrange(40)]
total=[]
for a,b,c in zip(chinese, math, English):
    total.append(a + b + c)
print(total)

2.某年级有4个班,某次考试每班的英语成绩分别存储在4个列表中,依次迭代每个列表,统计全学年成绩高于90分的人数。(串行)

串行->使用标准库中的itertools.chain, 它能够将多个迭代对象连接

from random import randint
from itertools import chain
class1=[randint(60,100) for _ in xrange(46)]
class2=[randint(60,100) for _ in xrange(47)]
class3=[randint(60,100) for _ in xrange(43)]
class4=[randint(60,100) for _ in xrange(50)]
count=0
for s in chain(class1, class2, class3, class4):
    if s > 90:
        count +=1        
print(count)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 本节课纲 可迭代对象 迭代器 生成器Python中内置的序列,如list、tuple、str、bytes、dict...
    郭_扬阅读 1,202评论 0 0
  • 迭代、迭代器、生成器、协程、yield、greenlet、gevent、进程线程协程对比、gevent多任务图片下...
    Cestine阅读 480评论 0 0
  • 一、总体内容 1.1、协程的介绍 1.2、迭代器以及迭代器的应用 1.3、生成器(生成器与迭代器保存的都是生成数据...
    IIronMan阅读 861评论 0 1
  • 更深入理解 Python 中的迭代 深入探讨 Python 的 for 循环来看看它们在底层如何工作,以及为什么它...
    lvyz0207阅读 2,501评论 3 10
  • 前言 在编写代码的过程中,我们常用面向对象的思维来组织与处理问题。 于是就有了类与对象的概念。根据类的描述,我们可...
    linheimx阅读 2,497评论 0 7