__iter__() 必须返回迭代器对象(含__next__()),若返回自身却未实现__next__(),则next()调用时报TypeError;其职责是提供新迭代器,而非自变迭代器。

为什么 __iter__() 返回的不是自己,next() 就会报错
因为 Python 的 for 循环和内置函数(如 list()、sum())只认「迭代器协议」:对象必须有 __iter__() 方法,且该方法返回一个带 __next__() 方法的对象。如果 __iter__() 直接返回 self,那它自己就得实现 __next__();如果没实现,调用 next() 时就会抛 TypeError: 'X' object is not an iterator。
常见错误现象:for item in my_obj: 报错说对象不可迭代,或 next(iter(my_obj)) 崩在 next() 上。
-
__iter__()的职责是「提供一个迭代器」,不是「让自己变成迭代器」 - 可迭代对象(如
list、自定义类)≠ 迭代器;迭代器是「一次性的、有状态的」 - 想复用,得每次调用
__iter__()都返回新迭代器实例,否则第二次for会空跑
next() 的第二个参数到底用来干啥
它是「哨兵值」,用于避免 StopIteration 异常。当迭代器耗尽时,不抛异常,而是直接返回这个默认值。
使用场景:读文件行、解析流式数据、做「尝试取一个」的逻辑,比如从配置里找第一个非空值。
立即学习“Python免费学习笔记(深入)”;
- 写成
next(iterator, None)是安全兜底,但要注意:返回None可能和真实数据冲突 - 别滥用——如果业务逻辑依赖「是否结束」,用
try/except StopIteration更清晰 - 性能无差异,但语义更明确:你主动选择了「静默终止」而非「异常控制流」
示例:next(iter([1, 2]), 'empty') → 1;next(iter([]), 'empty') → 'empty'
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
自定义类怎么同时支持 for 和 next()
关键在两层分离:类本身是可迭代对象,内部另写一个迭代器类(或用生成器),由 __iter__() 返回它。
容易踩的坑:把状态存在可迭代对象上,导致多次遍历相互干扰;或者忘记在迭代器里维护 self._index 这类状态变量。
- 迭代器必须实现
__next__(),且内部要有状态(如索引、游标、缓存) -
__iter__()每次都应返回新迭代器实例,例如return MyIterator(self.data) - 如果用生成器函数实现
__iter__()(yield),它天然满足迭代器协议,但无法共享状态,适合只读、无副作用场景
示例片段:
class Countdown:
def __init__(self, n):
self.n = n
def __iter__(self):
return CountdownIter(self.n)
class CountdownIter:
def __init__(self, n):
self.n = n
def __next__(self):
if self.n <= 0:
raise StopIteration
self.n -= 1
return self.n + 1
生成器函数 vs 手写迭代器类,选哪个
90% 场景用生成器函数就够了。def __iter__(self): yield from ... 或直接 yield,代码少、不易错、自动管理状态和异常。
手写类只在需要精细控制时才值得:比如要支持 .reset()、.peek()、多路并行迭代、或复用已有状态对象。
- 生成器函数返回的是
generator对象,它既是可迭代对象也是迭代器(iter(gen) is gen成立) - 手写类可以带额外方法(如
.close()、.send()),但日常几乎用不到 - 兼容性无差别,所有 Python 版本都支持;性能上生成器略快(C 层优化),但差距微乎其微
真正容易被忽略的点:生成器函数一旦执行完毕就不可重用,而手写类如果设计成每次 __iter__() 返回新实例,就能支持多次 for ——这点很多人以为「生成器更方便」,其实反而更难复用。

















