python iterable(可迭代对象) vs iterator(迭代器) vs sequence(序列) vs generator(生成器)
这四个概念是Python为了解决容器对象遍历问题抽象出来的概念. 三者之间的关系是:
可迭代对象 iterable
Python官方文档的定义如下:
An object capable of returning its members one at a time.
定义非常抽象, 中文翻译的也算精准, 凡是能够一次返回一个成员的容器对象都是可迭代对象. 理解上可以把可迭代对象对应数学上的可数集.(容器对象对应数学上的集合)
可数集分为有限可数集和无限可数集, iterable也分两类: sequence和iterator. 其中序列(sequence)对应数学里的有限可数集, 迭代器(iterator)可以类比于无限可数集(其实也是有限的, 只不过长度未知).
后面再分别细说这两种对象, 先说一下可迭代对象的用处.
最常用的是用在for
语句里(所以有些文章会把iterable定义为可以用在for
语句in
后面的对象).
当然还有很多其他语句里可以使用iterable.
比如built-in函数zip()
,map()
等,
或者推导式(comprehension). 但本质上还是for
语句的变体.
这里解释一下for语句在python里的本质.
下面的for
语句:
1 | for member in iterable_obj: |
实际上python是按照如下进行实现的:
1 | # 首先获得Iterator对象: |
这里built-in函数iter()
和next()
后面再详细解释.
判断一个对象是否是iterable, python的collections可以通过下面的方法.
1 | from collections import Iterable |
__iter__()
方法(直到python3.9)来确定其返回值.
但这个判断方法并不符合python对iterable的定义.也就是说并不是所有的iterable都具有__iter__()
方法.
所以我不推荐这个方法. 后面会讲到这种方法无法判断的例外.
想要确定一个对象是否是iterable, 即可以通过for语句遍历(即数学上可数的), 可以用如下函数:
1 | def isIterable(x): |
可见可迭代对象等定义在执行中等价于可以传递给built-in函数iter()
并且不抛出异常的对象.
这里dd额buit-in函数iter()
和特殊方法__iter__()
将在后面介绍.
序列 sequence
Python官方文档的定义如下:
An iterable which supports efficient element access using integer indices via the
__getitem__()
special method and defines a__len__()
method that returns the length of the sequence.
即能够做下面两种行为的iterable被叫做序列:
- 能够通过整数索引来做成员访问.
即具有方法
__getitem__()
并其参数可以是整数. - 能够获得长度, 即具有方法
__len__()
. 这也是为什么前面说sequence可以类比于有限可数集. 因为其具有长度.
这两个特殊方法加上整数索引合起来叫做序列协议(sequence
protocol).
实现了序列协议的iterable对象就可以叫做序列. 比如python built-in
sequence类型list
, str
, tuple
and
bytes
.
注意dict
虽然也有方法__getitem__()
和__len__()
,
但被认为是mapping而不是sequence,
因为不满足上面说的通过整数索引.
但是dict
是可迭代对象(iterable),
因为其可以逐一返回其容器内对象.
迭代器 iterator
Python官方文档的定义如下:
An object representing a stream of data. Repeated calls to the iterator's
__next__()
method (or passing it to the built-in functionnext()
) return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its__next__()
method just raise StopIteration again. Iterators are required to have an__iter__()
method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted.
迭代器是一种数据流的抽象. 迭代器的具体实现也是有两个行为:
- 实现
__next__()
方法, 这个方法返回的是数据流中的下一个成员. 当所有成员都遍历过了, 再次调用方法__next__()
, 必须抛出StopIteration
异常代表迭代器耗尽. python built-in函数next(obj)
等效于调用obj.__next__()
. - 实现
__iter__()
方法返回一个迭代器对象. 通常返回迭代器对象自身.
这两个方法合起来叫做迭代器协议(iterator protocol), 也就是说只要实现了这个协议的对象都成为迭代器. 可见满足迭代器协议的对象一定也满足迭代协议.
讲到这里就可以回到文章刚开始提起for
循环的本质
1 | # 首先获得Iterator对象: |
里面的built-in函数next()
已经知道是什么意思了.
现在说一下iter()
.
Python官方文档对这个内置函数描述如下:
iter(object[, sentinel]) Return an iterator object. The first argument is interpreted very differently depending on the presence of the second argument. Without a second argument, object must be a collection object which supports the iteration protocol (the
__iter__()
method), or it must support the sequence protocol (the__getitem__()
method with integer arguments starting at 0). If it does not support either of those protocols, TypeError is raised. If the second argument, sentinel, is given, then object must be a callable object. The iterator created in this case will call object with no arguments for each call to its__next__()
method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.
即这个函数会返回一个iterator对象.
如果没有第二个参数, 只有第一个参数
- 如果对象满足迭代协议,
obj.__iter__()
将被调用, 其返回值作为iter(obj)
的返回值. - 如果对象满足序列协议,
Python会自动通过
__getitem__
和__len__
方法自动产生一个迭代器, 这种情况大致上iter(obj)
等价于如下代码:
1 | def iter(obj): |
- 如果上面两条协议都不满足, 那么将抛出异常TypeError.
如果给了第二个参数sentinel,
第一个参数必须是一个可调用对象(callable object).
iter()
语义变成"通过对可调用对象的调用返回一系列值,
直到卫兵(sentinel)被调用的对象返回. iter(obj,
sentinel)大致上等价于如下代码:
1 | def iter(obj, sentinel): |
生成器 generator
Python官方文档的定义如下:
A function which returns a generator iterator. It looks like a normal function except that it contains yield expressions for producing a series of values usable in a for-loop or that can be retrieved one at a time with the
next()
function.Usually refers to a generator function, but may refer to a generator iterator in some contexts. In cases where the intended meaning isn’t clear, using the full terms avoids ambiguity.
这里generator在使用上是有歧义的, 既可能指生成器函数(generator function), 也可能指生成器迭代器(generator iterator). 本文里用generator指后者, 前者直接用生成器函数.
所以生成器是一种特殊迭代器, 由生成器函数产生的迭代器. 因而yield
表达式.
反复调用生成器函数可以产生一系列的值. 调用生成器函数, 函数体不会执行,
而是返回一个生成器. 然后当我满按照迭代器的使用, 遍历其成员的时候,
生成器的__next__()
方法通过执行生成器函数的函数体来产生一系列值.
下面的代码是一个generator, 可见其符合迭代器协议.
1 | def generator_fun(): |
转化
iterator转化为sequence可以通过类似于list(obj)
或者推导式(comprehension)来实现.
sequence转为为iterator可以通过iter(obj)
来实现.
总结
- iterable是可以放在for语句里的对象.也可以定义为可以传递给
iter()
的对象. - iterable可以通过iter(obj)转化为iterator
- iterable包含两类iterator和sequence
- sequence要符合sequence protocol,
即含有
__getitem__()
和__len__()
方法, 可整数索引. - iterator要符合iterator protocol,
即含有
__next__()
和__iter__()
方法 - generator是一种特殊的iterator, 调用含有yield语句的generator function(生成器函数), 将返回一个generator.
专有名词翻译
英文 | 中文 |
---|---|
comprehension | 推导式 |
generator | 生成器 |
generator function | 生成器函数 |
generator iterator | 生成器迭代器 |
iterable | 可迭代对象(可遍历对象) |
iterator | 迭代器 |
sequence | 序列(队列) |
Be the first person to leave a comment!