序列和可迭代
可迭代对象和迭代器
| 英文 | 中文 | 定义 | 必须实现的方法 |
| Iterable | 可迭代对象 | “可以被 for 遍历的东西” | __iter__(或旧协议 __getitem__) |
| Iterator | 迭代器 | “真正负责逐个吐出值的东西” | __iter__ + __next__ |
| Iteration protocol | 迭代协议 | 官方约定的接口 | 见下文 |
2 迭代协议(The Iterator Protocol)
Python 官网给出的两条规则:
可迭代对象
实现
def __iter__(self):return <iterator>迭代器
实现
def __iter__(self):return self # 迭代器本身也是可迭代对象def __next__(self): # Python 2 叫 next...return value# 没数据时抛 StopIteration协议工作流(for 循环伪代码):
_iter = obj.__iter__() # 先拿迭代器
while True:try:x = _iter.__next__() # 再不断拿值except StopIteration:break旧式序列协议:__getitem__
没有 __iter__ 但有
def __getitem__(self, index):...且索引从 0 开始,连续抛 IndexError 时,Python 会自动把它包装成迭代器。
典型例子:标准库 collections.abc.Sequence 的默认实现。
仅作兼容,写新代码请优先 __iter__。
序列和可迭代对象
“序列”一定是可迭代的,但“可迭代对象”未必是序列。
| 概念 | 抽象基类 | 必须实现的方法 | 额外保证 |
| 可迭代对象 Iterable | collections.abc.Iterable | __iter__ | 只能“逐个吐出值” |
| 序列 Sequence | collections.abc.Sequence | __getitem__ + __len__ | 还有长度、按下标取值、切片、反向遍历等能力 |
拆包对可迭代对象
拆包的目标可以是任何可迭代对象,包括不支持索引表示法([])的迭代器。拆包对可迭代对象的唯一要求是,一次只能产出一项,提供给接收端变量。不过也有例外,可以使用星号(*)捕获余下的项。
最明显的拆包形式是并行赋值(parallel assignment),即把可迭代对象中的项赋值给变量元组,如以下示例所示。
>>> lax_coordinates = (33.9425, -118.408056)
>>> latitude, longitude = lax_coordinates # 拆包
>>> latitude
33.9425
>>> longitude
-118.408056调用函数时在参数前面加上一个 *,利用的也是拆包。
>>> divmod(20, 8)
(2, 4)
>>> t = (20, 8)
>>> divmod(*t)
(2, 4)
>>> quotient, remainder = divmod(*t)
>>> quotient, remainder
(2, 4)