Python 迭代器与生成器实例详解
|
Python 迭代器与生成器实例详解 一、如何实现可迭代对象和迭代器对象 1.由可迭代对象得到迭代器对象 例如l就是可迭代对象,iter(l)是迭代器对象 In [1]: l = [1,2,3,4] In [2]: l.__iter__ Out[2]: <method-wrapper '__iter__' of list object at 0x000000000426C7C8> 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() --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-8-3660e2a3d509> in <module>() ----> 1 t.next() StopIteration: for x in l: print x for 循环的工作流程,就是先有iter(l)得到一个t,然后不停的调用t.nex(),到最后捕获到StopIteration,就结束迭代 # 下面这种直接调用函数的方法如果数据量大的时候会对网络IO要求比较高,可以采用迭代器的方法 def getWeather(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']) print getWeather(u'北京') 返回值: 实现一个迭代器对象WeatherIterator,next 方法每次返回一个城市气温 实现一个可迭代对象WeatherIterable,iter方法返回一个迭代器对象
# -*- coding:utf-8 -*-
import requests
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 '%s:%s,data['high'])
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([u'北京',u'上海',u'广州',u'深圳']):
print x.encode('utf-8')
输出:
北京:低温 13℃,高温 28℃
上海:低温 14℃,高温 22℃
广州:低温 17℃,高温 23℃
深圳:低温 18℃,高温 24℃
二、使用生成器函数实现可迭代对象 1.实现一个可迭代对象的类,它能迭代出给定范围内所有素数 素数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数的数称为素数。 一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
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,10):
print x
输出:
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
class FloatRange:
def __init__(self,end,step=0.1):
self.start = start
self.end = end
self.step = step
def __iter__(self):
t = self.start
while round(t,14) <= round(self.end,14):
yield t
t = t + self.step
def __reversed__(self):
t = self.end
while round(t,14) >= round(self.start,14):
yield t
t = t - self.step
for x in reversed(FloatRange(3.0,0.2)):
print x
输出:
4.0
3.8
3.6
3.4
3.2
3.0
for x in FloatRange(3.0,0.2):
上面代码采用round函数是因为浮点数比较会有精度问题,所以需要进行四舍五入 2.对迭代器进行切片操作 例如: 有某个文本文件,想读取其中某范围的内容,如100-300行之间的内容,python中文本文件是可迭代对象,是否可以使用类似列表切片的方式得到一个100-300行文件内容的生成器 使用标准库中的itertools.islice,它能返回一个迭代对象切片的生成器
f = open('/var/log/dmesg')
from itertools import islice
# 对文件内容100到300行之间进行切片,返回的是个生成器对象,默认i径是1
islice(f,100,300)
# 前500行内容
islice(f,500)
# 100行到末尾结束内容
islice(f,None)
ps: 每次使用islice要重新申请对象,它会消耗原来的迭代对象
四、 迭代多个对象 1.在一个for语句中迭代多个可迭代对象 1、某班学生考试成绩语文、数学、英语分别存储在3个列表中,同时迭代三个列表,计算三个学生的总分(并行) 2、某年级四个班,某次考试每班英语成绩分别存储在4个列表中,依次迭代每个列表,统计全学年英语成绩高于90分人数(串行) 解决方案: 并行: 使用内置函数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 c,m,e in zip(chinese,math,english): total.append(c+m+e) print total 输出: [204,227,238,201,205,251,274,210,242,220,239,237,207,230,267,263,240,247,249,255,268,209,270,259,245,262,234,221,236,250,232,272,253] 串行: 使用标准库中的itertools.chain,它能将多个可迭代对象连接
from random import randint
from itertools import chain
class1 = [randint(60,100) for _ in xrange(40)]
class2 = [randint(60,100) for _ in xrange(42)]
class3 = [randint(60,100) for _ in xrange(39)]
class4 = [randint(60,100) for _ in xrange(43)]
count = 0
for s in chain(class1,class2,class3,class4):
if s > 90:
count = count + 1
print count
输出:
38
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持! (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
