wordpress怎么发布文章,邢台做网站建设优化制作公司金信一条龙,网站开发及服务合同模板,什么是企业营销型网站在 Python 的对象模型中#xff0c;“生成器对象”#xff08;generator object#xff09;并不是独立于函数调用机制之外的全新执行体系#xff0c;而是在函数语义框架内#xff0c;通过改变调用与恢复规则而形成的一类特殊迭代器对象#xff1a;它在满足迭代协议的同时…在 Python 的对象模型中“生成器对象”generator object并不是独立于函数调用机制之外的全新执行体系而是在函数语义框架内通过改变调用与恢复规则而形成的一类特殊迭代器对象它在满足迭代协议的同时还额外承担了保存并恢复执行状态的职责用于描述一次可暂停、可恢复的函数执行过程。理解生成器对象是理解 yield 的真正语义、澄清“生成器 ≠ 生成器函数”、以及统一认识 Python 中“执行状态对象化”设计思想的关键一环。一、从生成器函数说起函数调用语义的改变在 Python 中只要函数体中出现 yield 表达式或 yield from 表达式该函数在定义阶段即被判定为生成器函数。def gen(): yield 1 yield 2这一判定发生在函数编译阶段。当函数体中包含 yield 或 yield from 时其代码对象会被标记为生成器代码对象CO_GENERATOR。随后在 def 语句执行时函数对象被创建并持有该代码对象。由此函数调用语义发生改变。生成器函数与普通函数的根本差异不只在于函数体内部多了 yield 表达式更重要的是由此发生的调用语义改变• 调用普通函数→ 创建执行帧→ 立即执行函数体→ 返回结果• 调用生成器函数→ 返回一个生成器对象→ 函数体并不立即执行因此生成器对象并不是函数执行的“中间结果”而是一次潜在执行过程的对象化表示。二、什么是生成器对象对象化的可恢复执行过程虽然二者都可以返回值但 yield 表达式与 return 语句在语义上有着本质区别。yield 的语义是在当前执行点产出一个值并暂停当前执行帧的执行状态。对比return终止函数执行执行帧退出调用栈yield暂停执行使执行帧保留在生成器对象内部以待恢复因此def f(): return 1 return 2与def g(): yield 1 yield 2的根本区别在于• f() 的执行过程不可恢复• g() 的执行过程是可暂停、可恢复、可推进的生成器对象正是这一“可恢复执行过程”在运行期的对象化表示。从对象模型角度看生成器对象是一种同时承担迭代器角色并持有执行阶段状态承载体执行帧的运行期对象。当执行g gen()gen() 被调用时解释器并不会执行函数体而是创建并返回一个生成器对象。type(g) # class generator此时函数体尚未开始执行。生成器对象内部已关联一个尚未启动的执行帧但该帧尚未进入指令执行阶段。因此生成器对象可以被视为对生成器函数“一次执行可能性”的封装一个尚未启动、但可被外部分阶段驱动的执行控制对象。需要指出的是生成器对象并不只来源于生成器函数。生成器表达式generator expression同样会在求值时返回一个生成器对象。例如g (x * 2 for x in range(3)) type(g) # class generator从语义层面看生成器表达式并不是“语法糖版的列表推导式”而是一种匿名的生成器函数结构。编译阶段生成器表达式会被转换为一个内部生成器函数并在求值时立即调用该函数从而返回一个生成器对象。因此• 生成器函数是“具名定义”• 生成器表达式是“匿名构造”但二者在运行期所得到的都是同一种生成器对象。换言之生成器对象是统一的运行期形态而生成器函数与生成器表达式只是不同的语法入口。三、生成器对象与迭代协议的关系从迭代协议角度看生成器对象满足迭代器对象的全部条件• 实现了 __next__• 实现了 __iter__并且 __iter__ 返回 self• 通过抛出 StopIteration 终止迭代验证g gen() iter(g) is g # Truenext(g) # 1next(g) # 2next(g) # StopIteration因此在迭代协议层面生成器对象不是类似迭代器而是一种有具体实现形式的迭代器对象。生成器对象之所以能被 for、next() 等机制驱动完全是因为它实现了迭代协议。def gen(): yield 1 yield 2 g gen() # for 循环只会调用 __iter__ 和 __next__for x in g: print(x) # 1 2四、生成器对象的核心职责保存与恢复执行帧生成器对象与一般迭代器对象本质上的差异在于它对执行帧的处理方式。当首次推进生成器对象时next(g)解释器的行为是1、恢复其内部已关联的执行帧2、从函数体起始位置开始执行3、执行至第一个 yield产出 yield 表达式的值4、暂停执行执行状态被保存在执行帧中生成器对象负责持有该执行帧并在后续调用中恢复它此后的每一次 next(g) 都不是重新调用函数更不会新建执行帧而是恢复此前保存的同一个执行帧从上一次 yield 之后继续执行。因此生成器对象的核心职责可以概括为在多次推进之间完整保存并恢复一次函数执行过程的执行阶段状态。这也是生成器对象能够实现“可暂停执行”的根本原因。五、生成器对象的“一次性”语义来源由于生成器对象描述的是一次具体的函数执行过程它天然具有“一次性”语义。g gen()list(g) # [1, 2]list(g) # []这里并不存在“生成器被清空”的行为而是该生成器对象所描述的执行过程已运行至终点其内部持有的执行帧已被释放。再次推进时不再存在可恢复的执行状态。从对象模型角度看• 容器对象描述“可反复使用的数据集合”• 生成器对象描述“一次具体的执行过程”因此生成器对象的“一次性”并非限制而是其语义定义的直接结果。六、生成器对象的扩展接口生成器对象具备一些额外的扩展接口用于对其执行过程进行显式控制。这些接口包括send()、throw() 与 close()。它们的共同特点是解释器在迭代语境中不会自动调用它们它们只服务于用户对执行过程的主动干预。由于生成器对象保存的是执行帧它不仅可以被动推进还可以在恢复执行时接收外部输入。def gen(): x yield 1 yield x执行过程g gen()next(g) # 产出 1g.send(hello) # 将 hello 注入这里需要强调的是send(value) 并不是向生成器对象“发送消息”而是将 value 作为上一次暂停点处 yield 表达式的求值结果该值随后参与函数体内部的后续执行。需要注意的是生成器在尚未启动前不能向其 send 非 None 的值否则会引发 TypeError因为此时还不存在可接收该值的 yield 表达式。当生成器不再只是“被动产出值”而需要与外部形成“可控的执行协作”时生成器对象的扩展接口就可真正发挥价值。也就是说当执行过程本身成为交互对象而不仅是数据来源时扩展接口才具有不可替代的意义。请参阅《Python生成器对象的扩展接口》 小结生成器对象是一类特殊的迭代器对象用于承载一次可暂停、可恢复的函数执行过程。它通过保存并恢复执行帧将函数执行状态对象化使其能够参与迭代协议与外部控制。生成器对象的“一次性”与可注入性并非附加特性而是其作为执行过程描述对象的必然语义结果。“点赞有美意赞赏是鼓励”