Python迭代器核心是iter()、next()及__iter__()/__next__()方法;for循环依赖对象是否实现这些协议;生成器函数通过yield返回可迭代的generator对象,其状态保存在帧对象中。
Python 里没有“迭代器系统学习路线第568讲”这种官方概念——iter()、next()、__iter__() 和 __next__() 就是全部核心,其余全是围绕它们的封装或语法糖。
for 循环能遍历列表但不能直接遍历整数因为 for 内部会自动调用 iter(obj),而该函数只对实现了 __iter__() 方法或支持序列协议(有 __getitem__ 且索引从 0 开始)的对象成功返回迭代器。整数没这两个方法,调用 iter(42) 直接抛 TypeError: 'int' object is not iterable。
常见误操作:
__iter__ 写成返回 self 却漏了 __next__ → 报 TypeError: iter() returned non-iterator
__next__ 里忘了抛 StopIteration → for 死循环yield 是怎么让函数变成迭代器的含 yield 的函数不是普通函数,而是生成器函数;调用它不执行逻辑,只返回一个 generator 对象——它既是迭代器(有 __iter__ 和 __next__),也是可迭代对象(能被 for 消费)。
关键点:
generator 的状态保存在帧对象(frame)里,每次 next() 恢复执行到上次 yield 处return 在生成器中等价于抛 StopIteration,其返回值可通过 exc.value 捕获(需用 try/except StopIteration as exc)next() 必报 StopIteration,不可重用def countdown(n):
while n > 0:
yield n
n -= 1
return "done"
g = countdown(2)
print(next(g)) # 2
print(next(g)) # 1
try:
next(g)
except StopIteration as e:
print(e.value) # done
标准 open() 返回的文件对象是迭代器,但它是逐行读取、无缓冲的;若想预读几行做判断(比如跳过注释、合并续行),就得自己控制 next() 调用节奏。
典型陷阱:
__next__ 中调 file.readline() 后不检查空字符串 → 遇到空行就提前终止list(file) 一次性读完,失去流式处理优势__del__ 或 close() 中关闭文件 → 句柄泄漏class BufferedLineIter:
def __init__(self, path):
self.file = open(path, 'r', encoding='utf-8')
self._buffer = []
def __iter__(self):
return self
def __next__(self):
if self._buffer:
return self._buffer.pop(0)
line = self.file.readline()
if not line:
self.file.close()
raise StopIteration
return line.rstrip('\n')
def peek(self, n=1):
while len(self._buffer) < n:
line = self.file.readline()
if not line:
break
self._buffer.append(line.rstrip('\n'))
return self._buffer[:n]真正难的不是写迭代器,而是判断什么时候该用迭代器、什么时候该用生成器表达式、什么时候干脆用列表推导式——这取决于你是否需要延迟计算、是否要多次遍历、内存是否敏感。别被“第568讲”吓住,翻源码看 itertoo
ls 里几个函数的实现,比追教程快得多。