Python中的迭代器(Iterator)
veekxt 发布于 2018-09-24 22:07:23

我们知道,可以用for语句来遍历如liststr等数据类型。这些数据称之为可迭代对象(Iterable),一个可迭代对象至少应满足两个条件之一:

  • 实现了__iter__()方法
  • 实现了__getitem__()方法

来看 for 是如何运行的,如果没有__iter__但有__getitem__,for 会使用下标来遍历,直到抛出IndexError异常,否则会尝试调用__iter__来返回一个**迭代器(iterator)**然后使用迭代器来遍历,那么什么是迭代器呢?迭代器必须实现:

  • __iter__()方法
  • __next__()方法

有了迭代器的__next__()方法,就可以不断调用next()(直到抛出 StopIteration 异常)来完成遍历了。

不过既然next足以帮我们完成遍历了,那么为什么要求实现__iter__()呢?根据for的运行原理,这是为了让迭代器也能作用于for,即迭代器也应该是迭代对象。那么问题绕到了一开始,为什么for要求实现__iter__()?这个问题的实质是,为什么要区分迭代器和可迭代对象?

我们知道,迭代器是通过next来不断取下一个值的,这意味着一个迭代器只能使用一次,但是有时我们希望可以多次遍历某个对象,典型的例子是一些内置的数据结构如list、tuple等:

li = [1, 2, 3, 4, 5]

# 第一次遍历
for i in li:
    pass
    
# li 是可迭代对象,但不是迭代器,可以重复遍历
for i in li:
    pass

为了能够重复遍历,Python 让 list 中的__iter__()每次都返回了新的迭代器。可见可迭代对象和迭代器区分是有意义的。那么如何自定义一个迭代器呢?比如我们要实现一个表示全体自然数的迭代器,它的结构应该是这样的:

class Nature():
    def __init__(self):
        self.i = 0
        
    def __iter__(self):
        # 这里应该返回一个迭代器
        pass
        
    def __next__(self):
        self.i+=1
        return self.i

具体如何实现__iter__呢,回想一下 for 的原理,__iter__应该返回一个迭代器,for 将使用该迭代器的__next__方法来访问下一个元素,显然我们想使用自身的__next__方法,因此只需要返回当前 Nature 对象:

    def __iter__(self):
        return self