迭代器和可迭代对象

下面大段内容转自:知乎 作者灵剑
这是个和多态有关的问题,Python中关于迭代有两个概念,第一个是Iterable,第二个是Iterator,协议规定Iterable的__iter__方法会返回一个Iterator, Iterator的__next__方法(Python 2里是next)会返回下一个迭代对象,如果迭代结束则抛出StopIteration异常。
同时,Iterator自己也是一种Iterable,所以也需要实现Iterable的接口,也就是__iter__,这样在for当中两者都可以使用。Iterator的__iter__只需要返回自己就行了。这样,下面的代码就可以工作:
for i in my_list:
    ...

for i in iter(mylist):
    ...

for i in (v for v in mylist if v is not None):
    ...

Python中许多方法直接返回iterator,比如itertools里面的izip等方法,如果Iterator自己不是Iterable的话,就很不方便,需要先返回一个Iterable对象,再让Iterable返回Iterator。生成器表达式也是一个iterator,显然对于生成器表达式直接使用for是非常重要的。
那么为什么不只保留Iterator的接口而还需要设计Iterable呢?许多对象比如list、dict,是可以重复遍历的,甚至可以同时并发地进行遍历,通过__iter__每次返回一个独立的迭代器,就可以保证不同的迭代过程不会互相影响。而生成器表达式之类的结果往往是一次性的,不可以重复遍历,所以直接返回一个Iterator就好。让Iterator也实现Iterable的兼容就可以很灵活地选择返回哪一种。

总结来说Iterator实现的__iter__是为了兼容Iterable的接口,从而让Iterator成为Iterable的一种实现。

for循环为了兼容性其实有两种机制,如果对象有__iter__会使用迭代器,但是如果对象没有__iter__,但是实现了__getitem__,会改用下标迭代的方式。我们可以试一下:
>>> class NotIterable(object):
...     def __init__(self, baselist):
...         self._baselist = baselist
...     def __getitem__(self, index):
...         return self._baselist[index]
...
>>> t = NotIterable([1,2,3])
>>> for i in t:
...     print i
...
1
2
3
>>> iter(t)
<iterator object at 0x0345E3D0>

 

当for发现没有__iter__但是有__getitem__的时候,会从0开始依次读取相应的下标,直到发生IndexError为止,这是一种旧的迭代协议。iter方法也会处理这种情况,在不存在__iter__的时候,返回一个下标迭代的iterator对象来代替。一个重要的例子是str,字符串就是没有__iter__接口的。
 
自定义可迭代对象和迭代器:
from collections import Iterator,Iterable
import requests,json

class WeatherItertor(Iterator):
    def __init__(self,city_list):
        self.CityList = city_list
        self.indexA = 0

    def getWeather(self,city):
        r = requests.get('http://www.weather.com.cn/data/sk/{code}.html'.format(code=city))
        ret = json.loads(r.content.decode("utf-8"))
        #风向
        WD = ret["weatherinfo"]["WD"]
        #城市
        city_data = ret["weatherinfo"]["city"]
        return "城市:{city},风向:{WD}".format(city=city_data,WD=WD)

    def __next__(self):
        if self.indexA == len(self.CityList):
            raise StopIteration
        city = self.CityList[self.indexA]
        self.indexA += 1
        return  self.getWeather(city)


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

    def __iter__(self):
        return WeatherItertor(self.CityList)



# citys = {'北京':101010100,'朝阳':101010300,'顺义':101010400,'怀柔':101010500}
citys_list = [101010100,101010300,101010400,101010500]
for x in  WeatherIterable(citys_list):
    print(x)

  

转载于:https://www.cnblogs.com/BGPYC/p/7502180.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值