迭代协议本身不提供组合操作符,但通过惰性求值和可链式构造新迭代器,支持封装filter、map等方法返回独立迭代器实例,实现类似.pipe()或链式调用的可组合遍历行为。

迭代协议本身不直接提供“组合操作符”(如 |、+ 或函数式链式调用),但它为构建可组合的遍历行为提供了底层基础。所谓“自定义组合操作符”,实际是指通过封装迭代逻辑,让多个遍历步骤能像管道一样拼接使用——比如 data.filter(...).map(...).take(5) 这类风格。这依赖于迭代协议的两个关键特性:**惰性求值**和**可链式构造新迭代器**。
把每种操作封装成返回新迭代器的工厂方法
不能在原对象上修改状态,而应每次返回一个**新的、独立的迭代器实例**,该实例持有原始数据 + 当前操作逻辑。这样就能支持任意嵌套和复用。
- __iter__ 方法只做一件事:返回新迭代器,不执行任何遍历逻辑
- 每个操作(如
filter、map)都定义为类的方法,内部创建并返回一个专用迭代器子类的实例 - 这些子类各自实现自己的
__next__,按需拉取上游迭代器的值、加工、再输出
用惰性迭代器链模拟“操作符”行为
例如实现 .map(f).filter(p) 链式调用:
-
MapIterator持有上游迭代器和函数f,每次__next__时调用next(upstream)再应用f -
FilterIterator同样持有上游,但__next__内部循环调用next(upstream)直到满足谓词p - 组合时,
filter的上游就是map的实例,形成单向数据流
这样写出来的代码看起来就像操作符组合:Chain([1,2,3]).map(lambda x: x*2).filter(lambda x: x > 3)。
支持类似 | 管道语法的技巧
Python 原生不支持中缀操作符重载(如 a | b 对自定义类),但可通过以下方式近似实现:
- 定义一个通用的
pipe函数:pipe(data, op1, op2, op3),依次把前一个结果传给下一个操作 - 让每个操作本身是可调用对象(如
class Map实现__call__),接收一个可迭代对象并返回新迭代器 - 利用生成器函数配合
yield from委托,让组合更轻量(例如def map(f, it): yield from (f(x) for x in it))
注意状态隔离与多次遍历支持
如果希望组合后的对象能被多次 for 循环使用(像列表一样),就不能让 __iter__ 返回自身,而必须每次新建迭代器:
- 容器类(如
Chain)只负责存储原始数据和操作栈 -
__iter__不运行逻辑,而是根据当前操作链动态构建完整迭代器链并返回 - 这样每次
for x in obj:都从头开始,互不影响
不复杂但容易忽略:所有中间迭代器必须严格遵循协议——__next__ 只返回有效值或抛 StopIteration,绝不返回 None 作为数据。











