直接for循环类实例报typeerror是因为未实现迭代器协议:必须定义__iter__方法并返回含__next__的迭代器对象;常见错误是遗漏__iter__或返回非迭代器。

为什么直接 for 循环类实例会报 TypeError: 'MyClass' object is not iterable
因为 Python 的 for 语句底层依赖迭代器协议:它会先尝试调用对象的 __iter__ 方法,若返回一个实现了 __next__ 的迭代器对象,才继续循环;否则直接报错。类本身不自动具备该协议,必须显式实现。
常见错误是只写 __next__ 却没配 __iter__,或 __iter__ 返回了非迭代器(比如直接返回 self 但没实现 __next__)。
-
__iter__必须返回一个对象,且该对象要有__next__方法(即迭代器对象) - 最简方案是让
__iter__返回self,但此时类必须同时实现__next__ - 如果类需支持多次独立迭代(如两次
for循环),就不能复用同一个实例作迭代器——否则第二次循环会从上次中断处继续,甚至直接抛StopIteration
如何正确实现单次可迭代的类(__iter__ + __next__)
适用于数据固定、只需一次遍历的场景,比如封装一个列表或生成一组计算值。关键点是状态管理:用实例属性(如 self._index)记录当前迭代位置,并在 __next__ 中更新和判断边界。
class Countdown:
def __init__(self, start):
self.start = start
<pre class="brush:python;toolbar:false;">def __iter__(self):
self._counter = self.start # 每次 for 都重置计数器
return self
def __next__(self):
if self._counter 注意:__iter__ 中重置 self._counter 是为了支持多次迭代;若省略这步,第二次 for 会立即触发 StopIteration。
- 不要在
__init__中初始化迭代状态(如self._index = 0),否则无法重复使用 -
__next__必须显式抛出StopIteration结束迭代,不能靠返回None或静默退出 - 若数据源是可变容器(如
list),建议在__iter__中缓存长度或引用,避免边迭代边修改导致行为异常
怎样支持多次独立迭代(返回新迭代器对象而非 self)
当类实例可能被多个地方同时迭代,或需要保持自身状态不变时,应该让 __iter__ 返回一个**独立的迭代器对象**,而不是 self。这样每次 for 都拿到干净的新迭代器。
class Numbers:
def __init__(self, data):
self.data = data # [1, 2, 3]
<pre class="brush:python;toolbar:false;">def __iter__(self):
return NumbersIterator(self.data) # 新对象,不污染 selfclass NumbersIterator: def init(self, data): self.data = data self.index = 0
def __next__(self):
if self.index >= len(self.data):
raise StopIteration
value = self.data[self.index]
self.index += 1
return value
def __iter__(self):
return self # 迭代器自己也是可迭代的
- 分离迭代逻辑到专用类,更清晰,也天然支持多路并发迭代
-
NumbersIterator.__iter__必须返回self,否则嵌套for或list()调用会失败 - 如果只是简单包装内置容器,可直接在
__iter__中返回iter(self.data),无需手写迭代器类
__iter__ 返回生成器函数时为什么不用写 __next__
因为生成器函数(含 yield)调用后返回的是一个生成器对象,它原生实现了迭代器协议。此时 __iter__ 只需返回这个生成器,Python 自动提供 __next__ 行为。
class Squares:
def __init__(self, n):
self.n = n
<pre class="brush:python;toolbar:false;">def __iter__(self):
for i in range(self.n):
yield i ** 2
这种写法简洁安全,且天然支持多次迭代(每次调用 __iter__ 都新建一个生成器)。但要注意:
- 生成器函数不能带状态重用逻辑(比如想“暂停后继续”需额外设计),适合一次性数据流
- 无法在生成器内部捕获
StopIteration并做清理——它由解释器自动处理 - 调试时生成器对象不显示中间变量值,比手动迭代器难追踪
真正容易被忽略的是:生成器方式虽省代码,但若类本身还需响应其他协议(如 __len__ 或索引),仍得单独实现,不能指望生成器自动补全。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











