1 可迭代对象和迭代器对象
Iterable,Iterator表示可迭代对象和迭代器对象。Iterator 从源码可以知道是继承了Iterable
from collections import Iterable,Iteratorl = [1,2,3,4]for x in l: # 能放到 in 后的一定是一个可迭代的print(x)
isinstance(l, Iterable) # Trueisinstance(l, Iterator) # Falseissubclass(list, Iterable) # Trueissubclass(str, Iterable) # Trueissubclass(dict, Iterable) # Trueissubclass(int, Iterable) # Falseiter(l)l.__iter__() # 和上面一样,都是可迭代对象
it = iter(l)next(it) #1list(it) #[2, 3, 4] 因为可迭代对象是一次性消费next(it) #StopIteration Traceback (most recent call last) 无就报错it = iter(l)isinstance(it ,Iterable) #Trueisinstance(it ,Iterator) #True
实例:迭代气温
import requestsurl = 'http://wthrcdn.etouch.cn/weather_mini?city='+'北京'r = requests.get(url)r.text # 文本形式显示r.json() # json形式返回
r.text返回如下
'{"data":{"yesterday":{"date":"16日星期六","high":"高温 12℃","fx":"北风","low":"低温 1℃","fl":"<![CDATA[3级]]>","type":"晴"},"city":"北京","forecast":[{"date":"17日星期天","high":"高温 14℃","fengli":"<![CDATA[2级]]>","low":"低温 2℃","fengxiang":"西南风","type":"晴"},{"date":"18日星期一","high":"高温 15℃","fengli":"<![CDATA[2级]]>","low":"低温 4℃","fengxiang":"东北风","type":"多云"},{"date":"19日星期二","high":"高温 13℃","fengli":"<![CDATA[2级]]>","low":"低温 2℃","fengxiang":"东北风","type":"晴"},{"date":"20日星期三","high":"高温 15℃","fengli":"<![CDATA[1级]]>","low":"低温 3℃","fengxiang":"西南风","type":"晴"},{"date":"21日星期四","high":"高温 17℃","fengli":"<![CDATA[2级]]>","low":"低温 4℃","fengxiang":"西北风","type":"晴"}],"ganmao":"感冒易发期,外出请适当调整衣物,注意补充水分。","wendu":"14"},"status":1000,"desc":"OK"}'
from collections import Iterable,Iteratorimport requestsclass WeatherIterator(Iterator):def __init__(self, cities):self.cities = citiesself.index = 0def get_weather(self, city):url = 'http://wthrcdn.etouch.cn/weather_mini?city=' + cityr = requests.get(url)data = r.json()['data']['forecast'][0]return city,data['high'],data['low']def __next__(self):if self.index == len(self.cities):raise StopIterationcity = self.cities[self.index]self.index += 1return self.get_weather(city)class WeatherIterable(Iterable):def __init__(self, cities):self.cities = citiesdef __iter__(self):return WeatherIterator(self.cities)def show(w):for x in w:print(x)w1 = WeatherIterable(['北京','合肥']*2)show(w1)print('-'*20)show(w1)

w1 = WeatherIterator(['北京','上海','合肥']*2)show(w1)print('-'*20)show(w1)
2 如何使用生成器函数实现可迭代对象
def f():print('1')yield 1print('2')yield 2f() #<generator object f at 0x7f9e125b0450>
g = f()from collections import Iterable,Iteratorisinstance(g, Iterable) #Trueisinstance(g, Iterator) #Trueiter(g) is g #Truenext(g)# 1# 1next(g)# 2# 2next(g)# StopIteration
实例:生成器创建可迭代对象
from collections import Iterableclass PrimeNumbers(Iterable):def __init__(self, a, b):self.a = aself.b = bdef __iter__(self): # 将该类的 __iter__方法实现生成器函数,每次yield返回一个素数for k in range(self.a, self.b + 1):if self.is_prime(k):yield kdef is_prime(self, k):return False if k < 2 else all(map(lambda x: k % x, range(2, k)))pn = PrimeNumbers(1, 30)for n in pn:print(n)
结果:
2357111317192329
3 如何实现反向迭代
不建议的方式
l = [1,2,3,4,5]l.reverse() # 会改变原来的listl #[5, 4, 3, 2, 1]l = [1,2,3,4,5]l[::-1] # 效果同上,但是占用内存空间
建议使用
reversed(fr)
实例
class FloatRange:def __init__(self, a, b, step):self.a = aself.b = bself.step = stepdef __iter__(self):t = self.awhile t <= self.b:yield tt += self.stepdef __reversed__(self):t = self.bwhile t >= self.a:yield tt -= self.stepfr = FloatRange(3.0, 4.0, 0.2)for x in fr:print(x)print('-'*20)for x in reversed(fr):print(x)
结果:
3.03.23.40000000000000043.60000000000000053.8000000000000007--------------------4.03.83.59999999999999963.39999999999999953.1999999999999993
和自己预计的有差异,这是因为使用二进制转化产生的差异,并逐个放大。
from decimal import Decimalclass 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.awhile t <= self.b:yield float(t)t += self.stepdef __reversed__(self):t = self.bwhile t >= self.a:yield float(t)t -= self.stepfr = FloatRange(3.0, 4.0, 0.2)for x in fr:print(x)print('-'*20)for x in reversed(fr):print(x)
3.03.23.43.63.84.0--------------------4.03.83.63.43.23.0
4 迭代器做切片操作
直接对f切片是不行的
f = open('t.txt')f[2:3] #TypeError: '_io.TextIOWrapper' object is not subscriptable
可切片的本质
l = list(range(6))l[2:4] #[2, 3] 切片操作实际是重载了这个函数:因此也可以写成 l.__getitem__(slice(2,4))
方法1:转成list
f = open('t.txt')l = f.readlines()# ['2020-12-1\n',# '2020-12-2\n',# '2020-12-3\n',# '2020-12-4\n',# '2020-12-5\n',# '2020-12-6\n',# '2020-12-7\n',# '2020-12-8\n']l[1:3] # ['2020-12-2\n', '2020-12-3\n']
方法2:自定义或使用函数
自定义
def myIslice(iterable, start, end, step=1):tmp = 0for i,x in enumerate(iterable):if i >= end:breakif i >= start:if tmp == 0:tmp = stepyield xtmp -= 1print(list(myIslice(range(100,130), 10, 20, 3))) #[110, 113, 116, 119]print(list(myIslice(f, 1, 3, 1))) #['2020-12-2\n', '2020-12-3\n']
函数形式
from itertools import islice
print(list(islice(range(100,130), 10, 20, 3))) #[110, 113, 116, 119]
f = open('t.txt')
print(list(islice(f, 1, 3, 1))) #['2020-12-2\n', '2020-12-3\n']
5 for语句中迭代多个可迭代对象
并行
使用内置函数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)]
#方式1
t = []
for s1, s2, s3 in zip(chinese, math, english):
t.append(s1 + s2 + s3)
#方式2
[sum(s) for s in zip(chinese, math, english)]
#方式3
list(map(sum, zip(chinese, math, english)))
#方式4
list(map(lambda s1,s2,s3: s1+s2+s3, chinese, math, english))
最后结果为列表的和形式。
list(map(lambda *args:args, chinese, math, english)) #和zip效果一样
串行
使用标准的库函数,itertools.chain,能将多个可迭代对象链接起来。
实例:统计数量大于90的人数
c1 = [randint(60, 100) for _ in range(20)]
c2 = [randint(60, 100) for _ in range(20)]
c3 = [randint(60, 100) for _ in range(20)]
c4 = [randint(60, 100) for _ in range(20)]
from itertools import chain
len([x for x in chain(c1,c2,c3,c4) if x > 90]) #19
