zoukankan      html  css  js  c++  java
  • Python内置类型(5)--迭代器类型

    指能够被内置函数next调用并不断返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值的对象称为迭代器(Iterator)

    其实以上的说法只是侠义上的迭代器的定义,在python中,迭代器还需要实现可迭代接口(Iterable),可迭代接口需要返回的是一个迭代器对象,这样迭代器就能够被for语句进行迭代。

    迭代器对象初步认知

    python中,没有内置迭代器类型的对象,但是可以通过内置函数iterstrtuplelistdictset等类型转换成一个迭代器对象。

    >>> s = 'abc'
    >>> next(s)
    Traceback (most recent call last):
    File "<pyshell#27>", line 1, in <module>
        next(s)
    TypeError: 'str' object is not an iterator
    # 以上报错信息可以看出`str`不是迭代器
    >>> it_s = iter(s)
    >>> next(it_s)
    'a'
    >>> next(it_s)
    'b'
    >>> next(it_s)
    'c'
    >>> next(it_s)
    Traceback (most recent call last):
    File "<pyshell#31>", line 1, in <module>
        next(it_s)
    StopIteration
    # 以上报错信息可以看出`iter(str)`是迭代器
    

    通过不断的调用next(iterator)方法来获取下一个值,这样其实不怎么方便,python提供了更为简洁的方法,即for循环。for循环每执行一次即相当于调用了一次next(iterator)方法,直到捕获到StopIteration异常退出循环。

    >>> it_s = iter(s)
    >>> for c in it_s:
        print(c)
    
    a
    b
    c
    
    # 以上的例子是使用for循环遍历迭代器
    

    模块collections中的类型Iterator就是迭代器的抽象基类,所有的迭代器都是Iterator的实例。即如果一个对象是Iterator的实例,则说明此对象是迭代器。

    from collections import Iterator
    
    >>> isinstance(s,Iterator)
    False
    
    >>> isinstance(it_s,Iterator)
    True
    
    # 以上信息证实了`str`不是迭代器,而`iter(str)`是迭代器
    

    如何自己实现一个迭代器

    根据python鸭子类型的特性,我们自定义的类型中,只要实现了__next()__方法,该方法在每次被调用时不断返回下一个值,直到无法继续返回下一个值时抛出StopIteration异常即可(next(iterator)实际上调用的是iterator内部的__next()__方法)。

    定义自己的迭代器

    >>> class MyIter():
    
        def __init__(self,max_value):
            self.current_value = 0
            self.max_value = max_value
    
        def __next__(self):
            if self.current_value < self.max_value:
                result = self.current_value
                self.current_value += 1
                return result
            else:
                raise StopIteration
    

    验证next方法是否不停返回下一个值

    >>> my_iter = MyIter(3)
    >>> next(my_iter)
    0
    >>> next(my_iter)
    1
    >>> next(my_iter)
    2
    >>> next(my_iter)
    Traceback (most recent call last):
      File "<pyshell#31>", line 1, in <module>
        next(my_iter)
    StopIteration
    

    验证对象是否可以用于for循环

    >>> my_iter = MyIter(3)
    >>> for i in my_iter:
        print(i)
    
    Traceback (most recent call last):
      File "<pyshell#5>", line 1, in <module>
        for i in my_iter:
    TypeError: 'MyIter' object is not iterable
    

    验证对象是否是Iterator实例

    >>> from collections import Iterator
    >>> isinstance(my_iter,Iterator)
    False
    

    从上面的验证可以看出仅仅实现__next()__方法的对象还不是迭代器,真正的迭代器还需要实现一个可迭代接口Iterable

    IteratorIterable的关系

    在模块collections中的类型Iterator就是迭代器的抽象基类,其实它里面还定义了类型Iterable,它是可迭代对象的抽象基类。先分别通过help命令查看他们的定义:

    >>> from collections import Iterator, Iterable
    >>> help(Iterator)
    Help on class Iterator in module collections.abc:
    
    class Iterator(Iterable)
     |  Method resolution order:
     |      Iterator
     |      Iterable
     |      builtins.object
     |  
     |  Methods defined here:
     |  
     |  __iter__(self)
     |  
     |  __next__(self)
     |      Return the next item from the iterator. When exhausted, raise StopIteration
     |  
     |  ----------------------------------------------------------------------
     |  Class methods defined here:
     |  
     |  __subclasshook__(C) from abc.ABCMeta
     |      Abstract classes can override this to customize issubclass().
     |      
     |      This is invoked early on by abc.ABCMeta.__subclasscheck__().
     |      It should return True, False or NotImplemented.  If it returns
     |      NotImplemented, the normal algorithm is used.  Otherwise, it
     |      overrides the normal algorithm (and the outcome is cached).
     |  
     |  ----------------------------------------------------------------------
     |  Data and other attributes defined here:
     |  
     |  __abstractmethods__ = frozenset({'__next__'})
    
    >>> help(Iterable)
    Help on class Iterable in module collections.abc:
    
    class Iterable(builtins.object)
     |  Methods defined here:
     |  
     |  __iter__(self)
     |  
     |  ----------------------------------------------------------------------
     |  Class methods defined here:
     |  
     |  __subclasshook__(C) from abc.ABCMeta
     |      Abstract classes can override this to customize issubclass().
     |      
     |      This is invoked early on by abc.ABCMeta.__subclasscheck__().
     |      It should return True, False or NotImplemented.  If it returns
     |      NotImplemented, the normal algorithm is used.  Otherwise, it
     |      overrides the normal algorithm (and the outcome is cached).
     |  
     |  ----------------------------------------------------------------------
     |  Data and other attributes defined here:
     |  
     |  __abstractmethods__ = frozenset({'__iter__'})
    

    通过上面的代码,可以清楚的看出迭代器类型Iterator继承自可迭代类型Iterable,可迭代Iterable继承自object基类,迭代器Iterator类型包含__iter()____next()__方法,而可迭代类型Iteratble仅仅包含__iter__()。可迭代对象,通过__iter()__返回一个迭代器对象,迭代器对象的__next()__方法则实际用于被循环。

    完善自己实现一个迭代器

    我们现在再将MyIter类型实现可迭代接口Iterable,即实现__iter__()方法。

    >>> class MyIter():
    
    def __init__(self,max_value):
        self.current_value = 0
        self.max_value = max_value
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current_value < self.max_value:
            result = self.current_value
            self.current_value += 1
            return result
        else:
            raise StopIteration
    

    验证对象是否可以用于for循环

    >>> my_iter = MyIter(3)
    >>> for i in my_iter:
    print(i)
    
    0
    1
    2
    

    验证对象是否是Iterator实例

    >>> from collections import Iterator
    >>> isinstance(my_iter,Iterator)
    True
    

    总结

    1. 凡是可作用于for语句循环的对象都是Iterable可迭代类型。
    2. 凡是可作用于next()函数的对象都是Iterator迭代器类型。
    3. strtuplelistdictset等类型是Iterable可迭代类型,但不是Iterator迭代器;通过Iterable可迭代类型的__iter()__方法可以获得一个Iterator迭代器对象,从而使得它们可以被for语句循环。
    4. Pythonfor循环本质上就是通过调用Iterable可迭代对象的__iter()__方法获得一个Iterator迭代器对象,然后不断调用Iterator迭代器对象__next()__方法实现的。
  • 相关阅读:
    筛选IPV4地址
    linux查看磁盘空间大小df du fdisk stat命令
    编写shell脚本sum求1100累加和
    postman通过Cookies登录博客园
    Linux中mount挂载命令简洁使用方法
    linux如何查询文件及文件夹大小
    postman接口测试中添加不同的断言
    设计模式之状态模式
    Docker安装SQL Server
    架构漫谈读书笔记
  • 原文地址:https://www.cnblogs.com/sesshoumaru/p/python-iterator.html
Copyright © 2011-2022 走看看