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() 方法进行迭代。

原文地址:https://www.cnblogs.com/stacklike/p/8109639.html