Python 迭代器协议的完整实现方式

14次阅读

完整迭代器必须同时实现__iter__和__next__:__iter__需返回含__next__的对象(通常为 self),__next__耗尽时须显式抛 StopIteration;状态应存于实例属性而非类属性;支持多次迭代需每次__iter__返回新实例;生成器函数可更安全地替代手动实现。

Python 迭代器协议的完整实现方式

__iter__ 和 __next__ 必须同时存在才能算完整迭代器

只实现 __iter__ 返回自身,却不定义 __next__,对象无法被 next() 调用,会抛出 TypeError: iterator does not have a __next__() method。反之,仅实现 __next__ 而没实现 __iter__,则无法用于 for 循环或 list() 等消费迭代器的场景,因为这些操作内部先调用 iter(),而 iter(obj) 要求对象必须有 __iter__ 方法(且返回一个迭代器)。

完整实现的关键是:

  • __iter__ 必须返回一个实现了 __next__ 的对象(通常是 self
  • __next__ 必须在耗尽时显式抛出 StopIteration,不能靠返回 None 或静默退出
  • 多次调用 iter() 应该能获得独立的迭代状态(除非你刻意设计为单次可迭代)

手动管理状态时容易忽略的边界情况

比如实现一个从 0 数到 n 的计数器迭代器,常见错误是把索引初始化写在类属性里,导致所有实例共享状态:

class BadCounter:     i = 0  # ❌ 类变量,所有实例共用     def __init__(self, n):         self.n = n     def __iter__(self):         return self     def __next__(self):         if self.i >= self.n:             raise StopIteration         val = self.i         self.i += 1         return val

正确做法是把状态放在实例属性中:

class GoodCounter:     def __init__(self, n):         self.n = n         self.i = 0  # ✅ 实例变量     def __iter__(self):         return self     def __next__(self):         if self.i >= self.n:             raise StopIteration         val = self.i         self.i += 1         return val

另一个易错点:__next__ 中未处理 self.i 超出范围的瞬间(比如 n=0 时首次调用就该抛异常),会导致无限循环或越界访问。

立即学习 Python 免费学习笔记(深入)”;

支持多次迭代需返回新迭代器实例

如果希望同一个对象能被多次 for 遍历(比如 listrange 的行为),就不能让 __iter__ 总是返回 self。否则第二次遍历时,内部状态已耗尽,直接抛 StopIteration

解决方式是让 __iter__ 每次都新建一个干净的迭代器:

class RepeatableRange:     def __init__(self, stop):         self.stop = stop     def __iter__(self):         return RepeatableRangeIterator(self.stop)  # ✅ 新实例 

class RepeatableRangeIterator: def init(self, stop): self.stop = stop self.i = 0 def next(self): if self.i >= self.stop: raise StopIteration val = self.i self.i += 1 return val def iter(self): return self

注意:RepeatableRangeIterator 自身也要实现 __iter__(返回自身),否则 iter(it) 会失败。

用生成器函数替代手动实现更安全

手动维护 __iter__ + __next__ 容易出状态错乱、漏抛 StopIteration、忘记重置等问题。Python 提供了更简洁可靠的替代:在 __iter__ 中返回一个生成器。

例如等价于上面 GoodCounter 的写法:

class GeneratorBasedCounter:     def __init__(self, n):         self.n = n     def __iter__(self):         i = 0         while i 

这种写法天然支持多次迭代(每次调用 __iter__ 都启一个新的生成器)、自动处理 StopIteration、无需手动管理状态变量生命周期。唯一要注意的是:生成器函数不能被 next() 直接调用(得先 iter()),但这本来就是迭代器协议的要求。

真正需要手写协议的场景其实很少——多数时候是封装底层流、资源或需要精细控制暂停 / 恢复逻辑时才值得深入。其他情况,生成器函数或 yield 就够用了。

text=ZqhQzanResources