2.1.1.1 迭代器

简洁

重复的工作是浪费,用一个标准的特性替代不同的自产方法通常使事物的可读性和共用性更好。 Guido van Rossum — 为Python添加可选的静态输入

迭代器是继承了迭代协议的对象-本质上,这意味着它有一个next方法,调用时会返回序列中的下一个项目,当没有东西可返回时,抛出StopIteration异常。

迭代器对象只允许循环一次。它保留了单次迭代中的状态(位置),或者从另外的角度来看,序列上的每次循环需要一个迭代器对象。这意味着我们可以在一个序列上同时循环多次。从序列上分离出循环逻辑使我们可以有不止一种方法去循环。

在容器上调用iter方法来创建一个迭代器对象是获得迭代器的最简单方式。iter函数帮我们完成这项工作,节省了一些按键次数。

In [12]:

  1. nums = [1,2,3] # 注意 ... 变化: 这些是不同的对象
  2. iter(nums)

Out[12]:

  1. <listiterator at 0x105f8b490>

In [2]:

  1. nums.__iter__()

Out[2]:

  1. <listiterator at 0x105bd9bd0>

In [3]:

  1. nums.__reversed__()

Out[3]:

  1. <listreverseiterator at 0x105bd9c50>

In [4]:

  1. it = iter(nums)
  2. next(it) # next(obj)是obj.next()的简便用法

Out[4]:

  1. 1

In [5]:

  1. it.next()

Out[5]:

  1. 2

In [6]:

  1. next(it)

Out[6]:

  1. 3

In [7]:

  1. next(it)
  1.  ------------- ------------- ------------- ------------- -----------------------
  2. StopIteration Traceback (most recent call last)
  3. <ipython-input-7-2cdb14c0d4d6> in <module>()
  4. ----> 1 next(it)
  5. StopIteration:

在一个循环上使用时,StopIteration 被忍受了,使循环终止。但是,当显式调用时,我们可以看到一旦迭代器结束,再访问它会抛出异常。

使用for..in 循环也使用iter方法。这个方法允许我们在序列上显式的开始一个循环。但是,如果我们已经有个迭代器,我们想要可以在一个循环中以同样的方式使用它。要做到这一点,迭代器及next也需要有一个称为iter的方法返回迭代器(self)。

Python中对迭代器的支持是普遍的:标准库中的所有的序列和无序容器都支持迭代器。这个概念也被扩展到其他的事情:例如文件对象支持按行循环。

In [10]:

  1. f = open('./etc/fstab')
  2. f is f.__iter__()

Out[10]:

  1. True

文件是迭代器本身,它的iter方法并不创建一个新的对象:仅允许一个单一线程的序列访问。