2.1 迭代器和可迭代对象
迭代器是指继承自Iterator,并实现了next方法的对象。使用迭代器的好处是节省内存,每次计算取下一个值即可。
可迭代对象指继承自Iterable实现了iter方法的对象,能够通过for循环等方法进行迭代。实现让一个对象变成可迭代对象,可以通过iter返回其构造的迭代器对象。
import requests
from collections import Iterator, Iterable
class WeatherIterator(Iterator):
def __init__(self, cities):
self.cities = cities
self.index = 0
def get_weather(self, city):
r = requests.get("http://wthrcdn.etouch.cn/weather_mini?city=" + city)
data = r.json()['data']['forecast'][0]
return "%s: %s, %s" % (city, data['low'], data['high'])
def __next__(self):
if self.index == len(self.cities):
raise StopIteration
city = self.cities[self.index]
self.index += 1
return self.get_weather(city)
class WeatherIterable(Iterable):
def __init__(self, cities):
self.cities = cities
def __iter__(self):
return WeatherIterator(self.cities)
if __name__ == "__main__":
test_cities = ['北京', '沈阳', '成都', '上海']
iterable = WeatherIterable(test_cities)
print(iterable)
for x in iterable:
print(x)
2.2 生成器
生成器是另一种方式将一个对象转换成可迭代对象,其特殊的地方在于用yield代替return,将当前状态和返回值进行了保存,方便之后进行迭代。生成器的应用场景主要是计算出来的大量结果不需要放进内存中,而是可以通过迭代的方式更加高效地完成任务。
class PrimeNumbers:
def __init__(self, start, end):
self.start = start
self.end = end
def is_prime(self, k):
if k < 2:
return False
for i in range(2, k):
if k % i == 0:
return False
return True
def __iter__(self):
for k in range(self.start, self.end + 1):
if self.is_prime(k):
yield k
if __name__ == "__main__":
prime = PrimeNumbers(0, 10)
for x in prime:
print(x)
2.3 反向迭代
对一个序列进行反向迭代,例如a = [1, 2, 3, 4],反向迭代变成[4, 3, 2, 1]。
方法有很多,a.reverse()方法可以反向迭代但是改变了a的值;a[::-1]通过列表切片可以反向迭代但是是生成了一个新的列表。
其实较好的操作是使用全局函数reversed(a),其生成了反向的迭代器对象,与iter(a)作用相似,只不过iter方法返回的是正向的迭代器。
class FroatRange:
def __init__(self, start, end, step):
self.start = start
self.end = end
self.step = step
def __iter__(self):
a = self.start
while a <= self.end:
yield a
a += self.step
def __reversed__(self):
a = self.end
while a >= self.start:
yield a
a -= self.step
if __name__ == "__main__":
froat = FroatRange(0, 3, 0.5)
for x in iter(froat):
print(x)
for y in reversed(froat):
print(y)
2.4 对迭代器进行切片操作
如何将一个迭代器像一个list或者字符串那样进行切片操作,可以使用itertools的islice
from itertools import islice
a = range(0, 10)
t = iter(a)
for x in islice(t, 0, 5):
print(x)
但是,如果使用了islice方法,会消耗t迭代器,意思就是说,当使用了islice进行切片操作,t也迭代到了对应位置上。
from itertools import islice
a = range(0, 10)
t = iter(a)
for x in islice(t, 0, 5):
print(x)
print("========================")
for y in t:
print(y)
其中,第二次迭代t,起始位置就变成了5.
2.5 使用for语句迭代多个对象
比较简单的做法是通过for循环可迭代对象的长度,然后根据索引迭代多个对象。此做法有些局限性,比如生成器是无法做到迭代长度的。
a = [1, 2, 3, 4]
b = ['a', 'b', 'c', 'd']
for index in range(len(a)):
print(a[index])
print(b[index])
比较通用的方法是使用zip函数,将多个可迭代对象分别取出对应索引的值,组成一个元组,然后包装城一个迭代器。
print(zip(a, b))
for x in zip(a, b):
print(x)
(1, 'a')
(2, 'b')
(3, 'c')
(4, 'd')
所以,迭代多个对象语句就变成了:
for x, y in zip(a, b):
print(x)
print(y)
上面属于并行迭代多个对象,还有一种情况是串行迭代多个对象。可以使用itertools的chain方法。
from itertools import chain
for x in chain(a, b):
print(x)
这样,a和b就是按照顺序串行迭代。