资讯中心

__iter__` / `__next__` 迭代器协议 vs yield生成器

📅 2026/8/25 5:51:30
__iter__` / `__next__` 迭代器协议 vs yield生成器
__iter__/__next__迭代器协议 vs yield生成器Python实现可迭代对象有两条路子手写类实现魔术方法__iter__、__next__写函数用yield自动生成迭代器生成器yield生成器本质Python帮你自动实现了__iter__和__next__的迭代器对象不用自己手写类。方式1手写迭代器类底层原始版本classCounter:def__iter__(self):self.n0returnselfdef__next__(self):ifself.n3:raiseStopIteration valself.n self.n1returnval cCounter()foriinc:print(i)执行过程for首先调用iter(c)→ 触发__iter__()返回迭代器实例循环反复调用next(迭代器)→ 触发__next__()当抛出StopIterationfor循环结束方式2yield生成器语法糖等价上面defcounter():n0whilen3:yieldn n1foriincounter():print(i)调用counter()返回一个生成器对象。这个生成器对象内部已经自带__iter__、__next__gcounter()print(hasattr(g,__iter__))# Trueprint(hasattr(g,__next__))# Truenext(g)→ 驱动函数运行碰到yield暂停返回产出值函数执行完毕自动抛出StopIteration不需要手动写raise对比手写类你自己维护状态变量self.nyield生成器由Python解释器帮你保存函数局部变量、执行位置。两者等价关系手写迭代器类yield生成器__next__返回值yield产出值raise StopIteration函数执行完毕自动抛出自己维护self.n状态解释器保存函数局部变量现场__iter__返回迭代器生成器的__iter__返回自己for循环工作原理伪代码objcounter()ititer(obj)whileTrue:try:itemnext(it)exceptStopIteration:break# 执行循环体print(item)不管是手写类迭代器还是yield生成器全部走这套逻辑。结合之前的 contextmanagercontextmanager就是拿生成器做上下文管理器fromcontextlibimportcontextmanagercontextmanagerdefmy_ctx():print(获取资源)try:yieldvaluefinally:print(释放资源)my_ctx()返回生成器对象with内部调用生成器的__next__()执行到yield暂停with块执行完再次调用__next__()继续跑yield后面finally清理代码如果with内部抛异常会在yield位置给生成器抛异常进入finally这就是为什么contextmanager必须把yield包在try‑finally不然异常发生时yield后面清理代码跑不到。关键小坑生成器只能遍历一次不管手写迭代器还是yield生成器迭代完毕就耗尽不能重复用。defgen():yield1yield2ggen()print(list(g))# [1,2]print(list(g))# [] 已经耗尽拿不到任何数据生成器是一次性普通容器list是可反复迭代。Swift对应类比Python手写__iter__/__next__→ Swift 遵守IteratorProtocolstructCounter:IteratorProtocol{varn0mutatingfuncnext()-Int?{ifn3{returnnil}defer{n1}returnn}}Swift返回nil代表迭代结束Python是抛StopIteration。Python yield生成器 → SwiftAnyIteratorSwift没有yield关键字需要手动写状态。小结yield不是什么魔法它是语法糖快速构建实现迭代器协议的对象。迭代器协议两个核心__iter__返回迭代器__next__产出下一个结束抛StopIteration。for循环底层就是不停调用next()捕获StopIteration结束。生成器一次性遍历完就空。contextmanager底层就是利用生成器的“暂停‑恢复”能力实现上下文管理器。