__iter__ 必须返回带__next__的对象,因迭代器协议要求分离可迭代对象与迭代器;直接返回值会触发TypeError。

为什么 __iter__ 必须返回一个带 __next__ 的对象,而不是直接返回值?
因为迭代器协议要求分离「可迭代对象」和「迭代器本身」。调用 iter(obj) 时,__iter__ 被触发,它必须返回一个新对象(通常是自身或新实例),这个对象要能响应 next() —— 即实现 __next__。如果 __iter__ 直接 return 42 或 yield 一个值,for 循环会报 TypeError: iter() returned non-iterator。
常见错误现象:TypeError: 'int' object is not iterable 或更具体的 TypeError: iter() returned non-iterator of type 'XXX',往往就是 __iter__ 返回了非迭代器类型。
-
__iter__的职责是“提供一个迭代器”,不是“开始迭代” - 多数情况下,返回
self是最简方案,但前提是类自己实现了__next__ - 若想支持多次独立遍历(比如多次
for循环),__iter__应返回新实例,而非self
自定义迭代器时,__next__ 抛 StopIteration 的时机怎么把握?
必须在「无更多数据可返回」的瞬间抛出,不能早、不能晚。早了(比如第一次就抛)会导致循环一次都不执行;晚了(比如已越界还返回旧值)会无限循环或返回脏数据。
使用场景:遍历列表、文件行、生成有限序列(如斐波那契前 N 项)都依赖这个边界判断。
立即学习“Python免费学习笔记(深入)”;
- 典型模式:用索引或状态变量跟踪进度,每次
__next__先检查是否越界,再取值,最后更新状态 - 切忌在
__next__开头就raise StopIteration—— 那等于拒绝所有迭代 - 不要用
return None代替raise StopIteration;Python 迭代器协议不认None为结束信号
示例(安全写法):
def __next__(self):
if self.index >= len(self.data):
raise StopIteration
value = self.data[self.index]
self.index += 1
return value
为什么用类实现迭代器比用生成器函数更难控制状态重用?
生成器函数(含 yield)每次调用 iter() 都返回全新生成器对象,天然支持多次遍历;而手写类迭代器若在 __iter__ 中返回 self,多次遍历会共享内部状态(如索引、缓存),第二次 for 循环可能直接从上次断点继续,甚至立即抛 StopIteration。
性能影响:返回新实例略慢(对象创建开销),但语义清晰;返回 self 轻量,但容易引发隐式 bug。
- 如果类设计目标是「单次消耗型」(如读取一次网络流),返回
self合理 - 如果期望行为像
list或range(可反复遍历),__iter__必须返回新对象,例如return MyIterator(self.data) - 别试图在
__next__里重置状态——这违反迭代器协议,for循环不会为你调用重置逻辑
iter(obj, sentinel) 形式下,自定义类怎么配合使用?
这种双参数 iter() 不走 __iter__,而是反复调用你传入的可调用对象(如函数),直到返回值等于 sentinel。它不依赖迭代器协议,所以你的类不需要实现 __iter__ 或 __next__,只需提供一个可调用接口。
使用场景:按块读文件、等待异步结果、轮询硬件状态等。
- 例如:
iter(f.read, b'')表示不断调用f.read(),直到返回空字节串 - 若你写了个类方法
read_chunk(),可传iter(obj.read_chunk, b''),无需任何协议方法 - 注意:该形式下,
obj本身不必是可迭代对象,也不触发__iter__
容易踩的坑:误以为这个 iter() 会调用类的 __iter__ —— 它完全绕过协议,只认 callable + sentinel。
__iter__ 返回什么、__next__ 怎么判终、以及是否允许外部多次调用 iter()。


















