• Python的程序结构[6] -> 迭代器/Iterator -> 迭代器浅析


    迭代器 / Iteratior


    目录

    1. 可迭代对象与迭代器协议
    2. 迭代器
    3. 迭代器(模拟)的建立 

    1 可迭代对象与迭代器协议


    对于迭代器首先需要了解两个定义,迭代器协议 (Iterator Protocol) 与可迭代对象 (Iterable) ,

    迭代器协议 Iterator Protocol:

    迭代器协议是指对象能够提供 next() 方法 (__next__()) ,返回迭代中的下一项,或者引起一个 StopIteration 异常,以终止迭代。

    可迭代对象 Iterable:

    可迭代对象则是指,实现了迭代器协议的对象,例如 list、tuple、dict 等,这些都属于可迭代对象 (Iterable),但是却不是迭代器对象 (Iterator)。但可以使用内建函数 iter(),利用可迭代对象生成一个迭代器对象。

    2 迭代器


    对于迭代器来说,需要的是一个 __next__() 特殊函数,也就是迭代器与可迭代对象的一个重要差别。通过示例可以看到,可迭代对象是不具有 __next__() 方法的,而迭代器则有。

    1 lis = [1, 2]  
    2 print(hasattr(lis, '__iter__')) # True  
    3 print(hasattr(lis, '__next__')) # False  
    4 lix = iter(lis)  
    5 print(hasattr(lix, '__iter__')) # True  
    6 print(hasattr(lix, '__next__')) # True  

    Note:

    1. 内置函数 iter() 会调用对象的 __iter__() 方法,因此,可迭代对象具有 __iter__() 方法;

    2. 内置函数 next() 会调用对象的 __next__() 方法,因此迭代器则需要具有 __next__() 方法;

    3. 当 for 循环处理可迭代对象时,其本质是先调用了可迭代对象的 __iter__() 方法,使其变成迭代器后,再进行 next() 循环迭代

    利用 help 函数分别查看两个对象,

    1 from collections import Iterator, Iterable  
    2 help(Iterator)  
    3 help(Iterable)  

    通过对迭代器的查看结果可以发现,Iterator 是以 Iterable 作为基类的,且多了一个 __next__() 方法。

    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__'})
    
    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__'})
    View Code

    3 迭代器(模拟)的建立


    对于一个迭代器的建立,主要是利用 iter() 函数调用可迭代对象内部的 __iter__() 函数返回一个迭代器对象。而此处将建立一个自己的类,来模拟迭代器的一些行为特征。建立的方式可分为两种,一种是直接建立 Iterator,另一种是继承 Iterable。

    直接建立 Iterator

    直接建立一个类 MyIterator,并完成迭代器必须的特殊方法 __next__ 的定义,同时加入了对 __iter__ 函数的定义,以便在for循环的时候返回实例本身(已具备 __next__ 方法因此只需返回实例即可,后面会介绍模拟可迭代对象的 for 循环迭代器生成)。定义的 __next__ 方法模拟了 range() 的行为。

     1 class MyIterator():
     2     def __init__(self, imin, imax):
     3         self.count = imin - 1
     4         self.limit = imax
     5 
     6     def __iter__(self):
     7         return self
     8 
     9     def __next__(self):
    10         self.count += 1
    11         if self.count >= self.limit:
    12             raise StopIteration
    13         return self.count
    14 
    15 it = MyIterator(0, 7)
    16 for i in range(7):
    17     print(next(it))
    18 # Output: 0 1 2 3 4 5 6
    19 
    20 for i in MyIterator(0, 7):
    21     print(i)
    22 # Output: 0 1 2 3 4 5 6

    利用 next() 和 for 循环两种方式遍历迭代器,可以看到输出正常。

    继承 Iterable

    第二种方式需要建立一个自己的可迭代对象,并模拟可迭代对象的行为。定义一个可迭代对象类 MyIterable,对可迭代对象不定义其 __next__ 方法,只定义 __iter__ 方法供 iter() 函数调用,在 __iter__ 方法中,将会利用一个 MyIterable 的子类 geneIterator (模拟 Iterator 基于 Iterable )来生成可迭代对象的子类迭代器。

     1 class MyIterable():
     2     def __init__(self, imin, imax):
     3         self.imin = imin
     4         self.imax = imax
     5         self.count = imin - 1
     6         self.limit = imax
     7 
     8     #def __iter__(self):
     9     #    return self
    10 
    11     def __iter__(self):
    12         return GeneIterator(self)

    这里定义了一个 MyIterable 的子类,GeneIterator 继承自 MyIterable,初始化时接收一个 Iterable 类实例作为参数,并且重载了一个 __next__() 函数用于实现迭代器的特性。

     1 class GeneIterator(MyIterable):
     2     def __init__(self, iterable):
     3       # This __init__ function pass two value to the instance of geneIterator
     4         MyIterable.__init__(self, iterable.imin, iterable.imax)
     5 
     6     def __next__(self):
     7         self.count += 1
     8         if self.count >= self.limit:
     9             raise StopIteration
    10         return self.count

    Note:

    此处最值得注意的是,GeneIterator(self) 中的 self MyIterable 的实例,作为初始化时传入参数iterable而存在,而 MyIterable.__init__(self, iterable.imin, iterable.imax) 中的 self 则是 GeneIterator 的实例,此处传入父类的初始化函数中的目的在于,让 self 通过 MyIterable 的初始化获得(继承) count limit 参数。

    最后验证迭代器

    1 for i in MyIterable(0, 7):
    2     print(i)
    3 # Output: 0 1 2 3 4 5 6

    通过上面两个类的继承关系,此处的 for 循环会先调用 MyIterable 的 __iter__ 方法,获得一个具有 __next__ 方法的 GeneIterator 实例,最终使用 next() 方法进行迭代。

  • 相关阅读:
    关于页面元素不可见的几种方法
    关于a标签点击禁止的
    v-bind 的作用 以及:key的作用
    v-model双向绑定的原理
    es6之babel
    父子组件之间的传参
    组件名学习
    PreparedStatement執行sql語句
    Statement执行DQL语句(查询操作)
    MySQL 插入数据时,中文乱码???问题的解决
  • 原文地址:https://www.cnblogs.com/stacklike/p/8109639.html
Copyright © 2020-2023  润新知