14. 实现可迭代对象和迭代器对象

例如,某天气软件要求,通过网络抓取各个城市气温信息,并依次显示:

北京:15 ~ 20
天津:17 ~ 22
长春:12 ~ 18
...

如果一次抓取所有城市气温信息再显示,显示第一个城市气温时,有很高的延时,并且浪费存储空间。

要求:以“用时访问”的策略,并将所有城市气温信息封装到一个对象里,可用for循环进行迭代。

解决方案:

Step1:实现一个迭代器对象WeatherIterator,它的__next__()方法每次返回一个城市的气温;

Step2:实现一个迭代器对象WeatherIterable,它的__iter__()方法返回一个WeatherIterator对象。


  • 对于Iterable类:
>>> from collections.abc import Iterable

>>> issubclass(int, Iterable)
False

>>> issubclass(str, Iterable)
True

>>> issubclass(list, Iterable)
True

>>> issubclass(dict, Iterable)
True

Iterable类是提供了__iter__()方法的抽象基类。iterable表示可迭代对象,即能够逐一返回其成员项的对象。可迭代对象被可用于for循环以及许多其他需要一个序列的地方(zip()map()、…)。当一个可迭代对象作为参数传给内置函数iter()时,它会返回该对象的迭代器。

使用isinstance(obj, Iterable)可以检测一个对象是否已经注册到Iterable或者实现__iter__()函数;但检测一个对象是否是可迭代对象的唯一可信赖的方法是调用 iter(obj)

  • 对于Iterator类:
>>> from collections.abc import Iterator

>>> issubclass(int, Iterator)
False

>>> issubclass(str, Iterator)
False

>>> issubclass(list, Iterator)
False

>>> issubclass(dict, Iterator)
False

Iterator类是提供了__iter__()__next__()方法的抽象基类,它继承Iterable类。iterator表示迭代器对象,即用来表示一连串数据流的对象。重复调用迭代器的__next__()方法(或将其传给内置函数next())将逐个返回流中的项。

迭代器必须具有__iter__()方法用来返回该迭代器对象自身,因此迭代器对象必定也是可迭代对象,但可迭代对象不一定是迭代器对象

  • IterableIterator区别:

判断是否是IterableIterator

isinstance(obj, Iterable)

isinstance(obj, Iterator)

凡是可以for循环的,都是Iterable;凡是可以next()的,都是Iterator。Iterable是一次性消费的,不同的Iterable之间没有关联。Python中的for循环就是通过next()实现的。

集合数据类型如list、truple、dict、str,都是Itrable不是Iterator,但可以通过iter()函数获得一个Iterator对象。


  • 方案示例:

使用迭代器:

from collections.abc import Iterable, Iterator
import requests

class WeatherIterator(Iterator):

    def __init__(self, cities):
        self.cities = cities
        self.index = 0


    def __next__(self):
        if self.index == len(self.cities):
            raise StopIteration
            
        city = self.cities[self.index]
        self.index += 1
        return self.get_weather(city)

    def get_weather(self, city):
        url = 'http://wthrcdn.etouch.cn/weather_mini?city=' + city
        r = requests.get(url)
        data = r.json()['data']['forecast'][0]
        return city, data['high'], data['low']


class WeatherIterable(Iterable):
    
    def __init__(self, cities):
        self.cities = cities

    def __iter__(self):
        return WeatherIterator(self.cities)


def show(w):
    for x in w:
        print(x)

w = WeatherIterable(['北京', '上海', '深圳'] * 3)
show(w)

结果:

('北京', '高温 33℃', '低温 20℃')
('上海', '高温 35℃', '低温 27℃')
('深圳', '高温 32℃', '低温 26℃')
('北京', '高温 33℃', '低温 20℃')
('上海', '高温 35℃', '低温 27℃')
('深圳', '高温 32℃', '低温 26℃')
('北京', '高温 33℃', '低温 20℃')
('上海', '高温 35℃', '低温 27℃')
('深圳', '高温 32℃', '低温 26℃')

通过迭代器对象,实现“用时访问”,每次返回一个城市的气温信息。可迭代对象类WeatherIterable必须要定义,因为迭代器对象是一次性的。


  • 方案示例:

使用生成器:

from collections.abc import Iterable
import requests

class WeatherIterable(Iterable):
    
    def __init__(self, cities):
        self.cities = cities

    def __iter__(self):
        for city in self.cities:
            yield self.get_weather(city)

    def get_weather(self, city):
        url = 'http://wthrcdn.etouch.cn/weather_mini?city=' + city
        r = requests.get(url)
        data = r.json()['data']['forecast'][0]
        return city, data['high'], data['low']


def show(w):
    for x in w:
        print(x)

w = WeatherIterable(['北京', '上海', '深圳'] * 3)
show(w)

结果:

('北京', '高温 33℃', '低温 20℃')
('上海', '高温 36℃', '低温 26℃')
('深圳', '高温 32℃', '低温 27℃')
('北京', '高温 33℃', '低温 20℃')
('上海', '高温 36℃', '低温 26℃')
('深圳', '高温 32℃', '低温 27℃')
('北京', '高温 33℃', '低温 20℃')
('上海', '高温 36℃', '低温 26℃')
('深圳', '高温 32℃', '低温 27℃')

通过生成器,不需要手动去维护迭代状态,生成器对象可以自动维护迭代状态,每次yield才返回一个气温信息。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值