迭代器和生成器,是Python语言的一大特定。这两个概念我们可能还不理解,但是我们前面的学习中已经有所接触,比如用for...in
遍历一个列表、字典、元组,就是使用了迭代器。
可迭代对象(iterable)
这个概念我们前面已经学过,这里提到是为了更好理解迭代器。从字面上看,可迭代对象和迭代器有很大关系,迭代器作用在可迭代对象上面,逐一返回可迭代对象的元素。也就是说,可以通过for
循环遍历的对象就可以称为可迭代对象。Python内置的数据类型中,是可迭代对象的有:str, list, tuple, dict, set
。这些数据结构都是用来存放其它对象的,也称为“容器”。
迭代器(iterator)
for
循环遍历列表(我们以列表为例,元组和字典等类似)的背后就是迭代器起的作用,Python有两个内置函数iter()
和next()
可以把这些可迭代对象显示转换为迭代器并进行遍历。先看看下面的代码:
In [1]: ll = [1,2,3]
In [2]: for n in ll:
...: print(n)
...:
1
2
3
In [3]: itr = iter(ll)
In [4]: itr?
Type: list_iterator
String form: <list_iterator object at 0x7fc0483c9828>
Docstring: <no docstring>
In [5]: next(itr)
Out[5]: 1
In [6]: next(itr)
Out[6]: 2
In [7]: next(itr)
Out[7]: 3
In [8]: next(itr)
----------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-8-6693cc261707> in <module>
----> 1 next(itr)
StopIteration:
通过iter()
内置函数,我们就可以得到list对象的迭代器(这实际上是调用的ll.__iter__()
),得到的是一个list_iterator
对象;然后我们就可以用内置函数next()
遍历这个迭代器(实际上是调用的ll.__next__()
)。每次调用next()
都能得到ll
的一个元素,其是按顺序依次返回ll
的元素,也就是说,迭代器机制了当前元素的位置。当元素遍历完毕时,就会引发StopIteration
的异常。从此,我们最初得到的迭代器itr
就不可以再迭代,因为它已经迭代到末尾。
通过上面的例子,我们可以看出一些迭代器的端倪。其实,迭代器就是定义了__iter__()
方法来返回一个带有__next__()
方法的对象的对象。按照这个定义,我们不用内置函数而是用__iter__()
和__next__()
来迭代一下列表对象:
In [9]: ll
Out[9]: [1, 2, 3]
In [10]: itr = ll.__iter__()
In [11]: itr
Out[11]: <list_iterator at 0x7fc048dcdcc0>
In [12]: itr.__next__()
Out[12]: 1
In [13]: itr.__next__()
Out[13]: 2
In [14]: itr.__next__()
Out[14]: 3
In [15]: itr.__next__()
----------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-15-fc6e27a9fb4c> in <module>
----> 1 itr.__next__()
StopIteration:
可以看出,这实现了和内置函数iter()
和next()
同样的效果。实际上,内置函数iter()
就是调用了迭代器的__iter__()
方法,而next()
就是调用了迭代器的__next__()
方法。
明白了迭代器的内部机制(称为“迭代器协议”),我们就可以在自定义类中添加迭代器行为了:
In [21]: class LessThan:
...: '''遍历比给定整数小的正整数的迭代器'''
...: def __init__(self, n):
...: self.n = n
...:
...: def __iter__(self):
...: return self
...:
...: def __next__(self):
...:
...: if self.n == 0:
...: raise StopIteration
...: self.n -= 1
...: return self.n
In [23]: lt = LessThan(5)
In [24]: lt
Out[24]: <__main__.LessThan at 0x7fc048d3acc0>
In [25]: iter(lt)
Out[25]: <__main__.LessThan at 0x7fc048d3acc0>
In [26]: for n in lt:
...: print(n, end=' ')
...:
4 3 2 1 0
lt
是我们自定义类LessThan
的一个对象,通过内置函数iter()
可以得到它的迭代器,它们两个完全一样,都是<__main__.LessThan at 0x7fc048d3acc0>
,因为内置函数和iter()
其实调用的就是lt.__iter__()
方法,而这个方法返回的就是它本身(带有__next__()
方法)。
总结
(1)可迭代对象:
可以通过for
循环遍历的对象都是可迭代对象。本质上,定义了__iter__()
方法或__getitem__()
方法的对象就是可迭代对象。
(2)迭代器:
定义了__next__()
方法的对象就是一个迭代器。迭代器迭代到末尾就会引起Stopiteration
异常。
(2)内置函数iter()
和next()
iter()
作用于可迭代对象得到迭代器;next()
对迭代器进行遍历。
(3)自定义类
自定义类中定义__iter__()
方法和__next__()
方法,实现迭代器;

我的公众号:猿人学 Python 上会分享更多心得体会,敬请关注。
***版权申明:若没有特殊说明,文章皆是猿人学 yuanrenxue.con 原创,没有猿人学授权,请勿以任何形式转载。***
哇塞,精彩,解决了我很多疑惑!