迭代器协议
对象必须提供一个 next() 方法
,执行该方法要么迭代下一项,要么就引起一个 StopIteration
异常以终止迭代(只能往后不能往前)—— 迭代器协议
协议是一种约定,可迭代对象实现了迭代器协议(for、sum、min、max 等使用迭代器协议访问对象)
可迭代对象(iterable)
实现了迭代器协议的对象,就是可迭代对象。如何实现迭代器协议:对象内部定义 __iter__()
方法。
可作用于 for
循环的对象统称为可迭代对象,能作用于 for
循环的数据类型有以下几种:
- 集合数据类型:
list
、str
、tuple
、dict
、tuple
等 - 生成器
generator
:包括生成器函数和带yield
关键字的生成器对象
可以用 isinstance()
判断一个对象是否是可迭代对象:
from collections import Iterable
isinstance([], Iterable) # True
isinstance('123', Iterable) # True
isinstance(123, Iterable) # False
可迭代对象是可迭代的(即能被 for 循环),但不是迭代器,因为 next()
函数无法调用它们:
next([1, 2, 3])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-38-4a6488f07b8e> in <module>()
----> 1 next([1, 2, 3])
TypeError: 'list' object is not an iterator # list 对象不是一个迭代器
但是可以用 iter()
函数将其转换为迭代器:
l = [1, 2, 3]
ret = iter(l) # 转换为迭代器
next(ret) # 调用 next() 函数
------------------------
1
迭代器(iterator)
可以被next()
函数调用并不断返回下一个值的对象称为迭代器:Iterator
。
迭代器对象从集合第一个元素开始访问,直到所有元素被访问完才算结束,只能往前不能往后。
使用isinstance()
判断一个对象是否是Iterator
对象:
from collections import Iterator
isinstance([], Iterator) # list 不是迭代器对象,False
isinstance(iter([1, 2, 3]), Iterator) # 用 iter() 将 list 转换为迭代器,True
isinstance((x for x in range(10)), Iterator) # 生成器是迭代器对象
迭代器惰性机制
迭代器表示的是一个数据流,可以调用 next()
函数不断返回下一个数据,直至没有数据抛出 StopIteration
。可以说它是一个有序序列,但我们不知道序列长度,只能通过 next()
函数实现按需计算下一个数据,所有它是惰性的,只有在需要时才计算返回下一个数据。
为什么要有迭代器
对于有序序列类型,使用索引以及 while 循环也难遍历所有元素,但是对于无序序列类型(字典、集合)就会束手无策。
for 循环机制
for
循环是基于迭代器协议提供了一个统一的可遍历所有对象的方法,调用对象的 __iter__()
方法将其转换为一个迭代器,再调用 __next__()
不断取出序列中元素。相比较迭代器而已,for
循环还完成了 StopIteration
的异常工作。
这样一来,只要是序列,都可以通过 for
循环遍历,不管是有序还是无序序列类型。
优缺点
优点:
- 提供一种不依赖于索引的迭代方式
- 惰性计算,节省内存(每次取值,才会加载)
缺点:
- 无法获取长度,
next()
完毕才知道 - 一次性,只能往前,不能往后
自定义类为迭代器
要想将自定义的类实现为一个迭代器,需要在类中实现 __iter__()
和 __next__()
方法:
__iter__()
方法:返回迭代器对象本身__next__()
方法:返回容器中下一个元素,当超出边界时触发StopIteration
异常终止迭代器
class Foo(object):
def __init__(self,step):
self.step = step
def __next__(self):
if self.step == 0:
raise StopIteration
self.step -= 1
return self.step
def __iter__(self):
return self
f = Foo(6)
for i in f:
print(i)
5
4
3
2
1
0
总结
- 可以
for
循环的对象都是可迭代类型 - 可以作用于
next()
函数的对象都是迭代器类型,它表示一个惰性计算的序列 list
、dict
、str
等都是可迭代的,但不是迭代器类型,因为没有next()
方法,可以用iter()
函数将其转换为迭代器- Python 的
for
循环机制其实质是不断调用next()
函数实现的,但是它超出边界不会触发StopIteration
for
循环一次将所有数取出,迭代器一次只取一个