Python迭代协议要求同时实现__iter__和__next__;仅__iter__返回自身却不定义__next__会导致next()报错,因可迭代对象与迭代器角色分离,__iter__必须返回含__next__的对象,__next__须状态可续且显式抛StopIteration。

Python 的迭代协议不是语法糖,而是明确由 __iter__ 和 __next__ 两个方法共同支撑的底层机制;只要实现了它们,对象就能被 for、list()、next() 等直接使用。
为什么只实现 __iter__ 不够?
常见误解是“只要返回一个可迭代对象就行”,但若 __iter__ 返回的是自身(即 self),而没定义 __next__,调用 next() 就会报 TypeError: 'X' object is not an iterator。因为「可迭代对象」和「迭代器」在协议中是两类角色:
-
__iter__的职责:返回一个迭代器(必须带__next__) -
__next__的职责:返回下一个值,或抛出StopIteration - 一个类可以同时是可迭代对象 + 迭代器(即 self 返回 self,且自己实现
__next__),但不能只做一半
__iter__ 返回什么才合法?
它必须返回一个实现了 __next__ 方法的对象 —— 可以是:
- 另一个类的实例(如自定义迭代器类)
- 内置类型,如
iter([1,2,3])、enumerate(...)、range(...) - 生成器函数(含
yield)返回的 generator 对象,天然支持__next__
错误写法示例(看似返回了列表,实则破坏协议):
立即学习“Python免费学习笔记(深入)”;
def __iter__(self):
return [1, 2, 3] # ❌ 列表没有 __next__,不是迭代器正确写法之一(委托给内置迭代器):
def __iter__(self):
return iter(self._data) # ✅ iter() 返回真正的迭代器
__next__ 怎么写才算合规?
它必须满足两个硬性条件:有明确的终止信号,且每次调用状态可延续。典型结构是:
- 用实例变量(如
self._index)保存当前进度 - 访问数据时检查越界,触发
raise StopIteration - 不返回
None或静默退出,否则for循环会无限卡住
示例(手动管理索引):
class Countdown:
def __init__(self, start):
self.start = start
def __iter__(self):
return self # 自身是迭代器
def __next__(self):
if self.start <= 0:
raise StopIteration
self.start -= 1
return self.start + 1注意:如果 __iter__ 返回的是新对象(比如每次 for 都新建一个迭代器),那 __next__ 就不该依赖外部可变状态,否则多个循环会互相干扰。
常见陷阱与调试建议
实际写的时候最容易漏掉的是状态隔离和异常边界:
- 多次调用
__iter__应返回独立的迭代器(除非你明确要共享状态) -
__next__中不要用print()或日志干扰返回值逻辑 - 测试时别只用
for,务必手动调用next(it)多次,直到StopIteration被抛出 - 如果数据源本身是惰性的(如文件行、数据库游标),
__next__里做 IO 是合理的;但如果是内存列表,反复计算索引比缓存结果更慢
协议本身很简单,但真正难的是让状态管理既安全又符合直觉 —— 尤其当对象既要被多次遍历,又要支持中途 break 或嵌套循环时。










