Python的程序结构[6] -> 迭代器/Iterator -> 迭代器浅析
迭代器 / Iteratior
目录
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__'})
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() 方法进行迭代。