深入理解python迭代器和生成器
理解介质
range
__iter__
__next__
iter()
next()
yield
getitem()
__getitem__
术语
sequence – 序列
一种 iterable,它支持通过 getitem() 特殊方法来使用整数索引进行高效的元素访问,并定义了一个返回序列长度的 len() 方法。内置的序列类型有 list、str、tuple 和 bytes。注意虽然 dict 也支持 getitem() 和 len(),但它被认为属于映射而非序列,因为它查找时使用任意的 immutable 键而非整数。
collections.abc.Sequence 抽象基类定义了一个更丰富的接口,它在 getitem() 和 len() 之外又添加了 count(), index(), contains() 和 reversed()。 实现此扩展接口的类型可以使用 register() 来显式地注册
iterable – 可迭代对象
能够逐一返回其成员项的对象。 可迭代对象的例子包括所有序列类型 (例如 list, str 和 tuple) 以及某些非序列类型例如 dict, 文件对象 以及定义了 iter() 方法或是实现了 序列 语义的 getitem() 方法的任意自定义类对象。
可迭代对象被可用于 for 循环以及许多其他需要一个序列的地方(zip()、map() …)。当一个可迭代对象作为参数传给内置函数 iter() 时,它会返回该对象的迭代器。这种迭代器适用于对值集合的一次性遍历。在使用可迭代对象时,你通常不需要调用 iter() 或者自己处理迭代器对象。for 语句会为你自动处理那些操作,创建一个临时的未命名变量用来在循环期间保存迭代器。参见 iterator、sequence 以及 generator。
iterator – 迭代器
用来表示一连串数据流的对象。重复调用迭代器的 next() 方法(或将其传给内置函数 next())将逐个返回流中的项。当没有数据可用时则将引发 StopIteration 异常。到这时迭代器对象中的数据项已耗尽,继续调用其 next() 方法只会再次引发 StopIteration 异常。迭代器必须具有 iter() 方法用来返回该迭代器对象自身,因此迭代器必定也是可迭代对象,可被用于其他可迭代对象适用的大部分场合。一个显著的例外是那些会多次重复访问迭代项的代码。容器对象(例如 list)在你每次向其传入 iter() 函数或是在 for 循环中使用它时都会产生一个新的迭代器。如果在此情况下你尝试用迭代器则会返回在之前迭代过程中被耗尽的同一迭代器对象,使其看起来就像是一个空容器。
generator – 生成器
返回一个 generator iterator 的函数。它看起来很像普通函数,不同点在于其包含 yield 表达式以便产生一系列值供给 for-循环使用或是通过 next() 函数逐一获取。
通常是指生成器函数,但在某些情况下也可能是指 生成器迭代器。如果需要清楚表达具体含义,请使用全称以避免歧义。
generator iterator – 生成器迭代器
generator 函数所创建的对象。
每个 yield 会临时暂停处理,记住当前位置执行状态(包括局部变量和挂起的 try 语句)。当该 生成器迭代器 恢复时,它会从离开位置继续执行(这与每次调用都从新开始的普通函数差别很大)。
generator expression – 生成器表达式
返回一个迭代器的表达式。 它看起来很像普通表达式后面带有定义了一个循环变量、范围的 for 子句,以及一个可选的 if 子句。 以下复合表达式会为外层函数生成一系列值
实验
可迭代对象
1 | # 简单可迭代对象 |
迭代器
1 | # 简单迭代器 __next__ __iter__ |
生成器和生成器迭代器
1 | # 生成器 |
生成器表达式
1 | # 生成器表达式 |
总结
可迭代对象
- 可迭代对象必须具有 iter() 方法 和 getitem() 方法
- 可迭代对象本身不支自遍历(即
__next__()
方法) - 可复用
迭代器
- 迭代器必须具有 iter() 方法 和 next() 方法
- 迭代器本身不支持切片(即
__getitem__()
方法) - 不能复用
生成器
- 返回生成器迭代器(generator iterator)的函数
- 含有
yield
关键字
生成器迭代器
- 生成器(generator)函数所创建的对象