Python 的“迭代”并不是一组语法,而是一种行为约定(protocol)。

当我们在使用 for 循环、生成器、推导式或内置函数(如 sum()、max()、sorted())时,底层都在遵循同一套迭代协议。

理解迭代协议,意味着真正理解 Python 世界中“数据流动”的机制。

一、什么是迭代协议

迭代协议(Iteration Protocol)是 Python 用来统一访问序列数据的一种约定。

任何对象,只要遵守以下两条规则,就能参与迭代操作:

实现 __iter__() 方法,返回一个迭代器对象。

迭代器对象实现 __next__() 方法,每次调用返回下一个元素。

这就是所谓的“可迭代对象 + 迭代器对象”机制。

换句话说,Python 不关心对象的具体类型,只要它实现了这两个方法,就被视为“可迭代”的。这正体现了 Python 的鸭子类型(Duck Typing)思想。

二、迭代协议的执行过程

当你编写一段 for 循环时,例如:

for x in [10, 20, 30]:
    print(x)

解释器实际上执行了以下等价逻辑:

iter_obj = iter([10, 20, 30])   # 调用 __iter__()
while True:
    try:
        item = next(iter_obj)   # 调用 __next__()
        print(item)
    except StopIteration:
        break

也就是说:

• iter() 触发对象的 __iter__() 方法,返回一个迭代器;

• next() 触发迭代器的 __next__() 方法,取出下一个元素;

• 当没有数据时,__next__() 抛出 StopIteration 异常,循环结束。

这个三步过程(iter → next → StopIteration)就是迭代协议的核心。

三、__iter__():迭代的入口

迭代协议从 __iter__() 开始,它告诉 Python:“我可以被迭代”。

任何实现了 __iter__() 方法的对象,都能用于 for 循环、推导式、sum() 等操作。

class Numbers:
    def __init__(self, n):
        self.n = n

    def __iter__(self):
        print("调用 __iter__(),返回一个迭代器对象")
        return iter(range(self.n))  # 调用内置 range 的迭代器

for num in Numbers(3):
    print(num)

输出:

调用 __iter__(),返回一个迭代器对象
0
1
2

此处 Numbers 自身不是迭代器,但通过实现 __iter__(),它变成了可迭代对象(Iterable)。

当执行 for 语句时,Python 会调用可迭代对象的 __iter__() 方法来生成一个新的迭代器。

四、__next__():迭代的推进

__next__() 方法定义了“下一步该返回什么数据”。它属于迭代器对象(Iterator)的职责。

示例:我们自己实现一个简单迭代器。

class Counter:
    """迭代器:从 1 递增到 n"""
    def __init__(self, n):
        self.current = 1
        self.n = n

    def __next__(self):
        if self.current <= self.n:
            val = self.current
            self.current += 1
            return val
        else:
            raise StopIteration

    def __iter__(self):
        return self  # 迭代器应返回自身

使用方式:

for i in Counter(3):
    print(i)

输出:

1
2
3

Counter 同时实现了 __iter__() 和 __next__(),因此它既是可迭代对象,也是迭代器对象。

五、迭代协议的兼容机制

在 Python 2 中还没有 __iter__() 方法,因此解释器提供了一种兼容机制:若对象没有定义 __iter__(),则尝试使用 __getitem__() 从索引 0 开始连续取值,直到抛出 IndexError 为止。

例如:

class Legacy:
    def __init__(self, seq):
        self.seq = seq

    def __getitem__(self, index):
        return self.seq[index]  # 旧式协议:逐项返回

for x in Legacy("abc"):
    print(x, end=' ')

输出:

a b c

Python 内部的逻辑相当于:

try:
    index = 0
    while True:
        value = obj[index]
        ...
        index += 1
except IndexError:
    pass

这种“回退策略”确保了旧代码仍能在 Python 3 中正常工作。

六、生成器与迭代协议

生成器(generator) 是迭代协议的天然实现者。

由 yield 语句定义的函数,会自动生成一个同时具有 __iter__() 与 __next__() 的对象。

def squares(n):
    for i in range(n):
        yield i * i  # 自动实现 __next__()

g = squares(5)

print(next(g))  # 0
print(next(g))  # 1

for val in g:
    print(val)  # 继续输出 4, 9, 16

输出:

0
1
4
9
16

生成器无需显式定义类,它的运行逻辑完全符合迭代协议:

• iter(g) 返回自身;

• next(g) 产出下一个值;

• 结束时自动抛出 StopIteration。

七、抽象基类与迭代协议

Python 的 .abc 模块定义了几个与迭代协议相关的抽象基类(ABC):

Iterable:拥有 __iter__() 方法的对象;

Iterator:既有 __iter__() 又有 __next__() 的对象。

from collections.abc import Iterable, Iterator

lst = [1, 2, 3]
it = iter(lst)

print(isinstance(lst, Iterable))  # True
print(isinstance(lst, Iterator))  # False
print(isinstance(it, Iterator))   # True

输出:

True
False
True

• 列表是可迭代对象,但不是迭代器。

• iter(lst) 返回的迭代器对象才具备 __next__() 方法。

八、扩展协议:反向与异步迭代

Python 还定义了若干迭代协议的扩展形式,用于特殊场景。

1、反向迭代协议

如果对象实现了 __reversed__(),就能被 reversed() 调用:

class Words:
    def __init__(self, text):
        self.words = text.split()

    def __reversed__(self):
        return reversed(self.words)

for w in reversed(Words("Python is fun")):
    print(w)

输出:

fun
is
Python

2、异步迭代协议

在异步环境中,迭代协议也有对应形式:

__aiter__():返回一个异步迭代器;

__anext__():定义每次异步取值的逻辑。

用于 async for 循环中。

小结

迭代协议是 Python 数据访问的统一接口:无论底层数据来自列表、文件、网络流或生成器,只要遵守 __iter__() 与 __next__() 的契约,它就能与 for、sum()、map() 等语言特性无缝协作。

这正体现了 Python 的“协议化思维”:只需行为兼容,而非类型继承。

迭代协议是 Python 数据流的灵魂,它让一切“可以被遍历的事物”在同一规则下运行,实现了真正的统一与优雅。

点赞有美意,赞赏是鼓励