zoukankan      html  css  js  c++  java
  • 迭代器和可迭代对象

    下面大段内容转自:知乎 作者灵剑
    这是个和多态有关的问题,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)
    

      

  • 相关阅读:
    MSDN Magazine搞错了
    Visual Studio 2005中设置调试符号(Debug Symbols)
    BCB 6的问题
    吴裕雄天生自然Spring Boot使用Spring Data JPA实现人与身份证的一对一关系映射
    吴裕雄天生自然Spring BootSpring Data JPA
    吴裕雄天生自然Spring BootSpring Boot对JSP的支持
    吴裕雄天生自然Spring BootSpring Boot的异常统一处理
    吴裕雄天生自然Spring Boot使用Spring Data JPA实现Author与Article的一对多关系映射
    吴裕雄天生自然Spring Boot解决 Error creating bean with name 'entityManagerFactory' defined in class path resource
    吴裕雄天生自然Spring Boot@ExceptionHandler注解和@ControllerAdvice注解
  • 原文地址:https://www.cnblogs.com/BGPYC/p/7502180.html
Copyright © 2011-2022 走看看