Python 进阶
Python 协程实现原理
dict 和 set 实现原理
Python 线程安全
Python 抽象语法树(AST)
Python 日志输出
Python 扩展入门(一)
Python 程序执行原理
Python 垃圾回收
Python 动态创建类
检查工具
PyFrameObject
yield 生成器工作原理
dict 设计与实现
Python 性能分析原理
PyCodeObject
Python 弱引用
Python 性能分析原理(二)
Python 源码分析(一)
Python Annotated
Python 依赖注入
python freelist
python代码编译成pyc
Python mmap 内存映射文件
Python值得学习的内容
async Future 对象
asyncio loop的实现
asyncio.sleep 的实现
asyncio 原理
Python 代码加密
Python Token类型
Python 扩展入门(二)
Python 性能优化
本文档使用 MrDoc 发布
-
+
首页
yield 生成器工作原理
### 概述 在Python中,`yield关键字用来创建生成器`。生成器的内部工作机制是通过一个称为**“帧对象”**的数据结构来实现的,这个帧对象保存了生成器的执行状态,包括它的局部变量和指令计数器等。 ### Python解释器中的生成器实现 Python解释器是在C语言中实现的,特别是CPython实现。以下提供一些有关生成器实现的关键点: **1. 解释器的字节码和帧:** - 每个Python函数都有一个字节码表示,称为py_code。 - 当函数被调用时,解释器会创建一个新的帧对象(`PyFrameObject`)来执行字节码。 **2. 生成器对象和帧:** - 对于生成器函数,解释器在函数调用时不会立即执行字节码,而是创建一个生成器对象`PyGenObject`。 - 生成器对象包含了帧对象(`PyFrameObject`),这个帧对象用来保存函数的局部变量、指令位置等执行状态,使函数可以在不同的yield点暂停和恢复执行。 - **状态切换过程**:当生成器函数执行到 yield 语句时,`PyFrameObject` 保存了执行状态。下一次调用生成器的 `__next__()` 或 `send()` 方法时,从上次的状态继续执行。 - **管理执行流**:`PyGenObject`负责管理生成器的整个执行流,包括维护生成器是否已经完成、当前执行位置等。 **3. 生成器的执行:** - 当生成器首次调用`__next__`方法时,解释器会执行生成器帧的字节码,直到遇到`yield`。 - 在执行到yield时,生成器帧的状态(包括局部变量和值)会被保存,以便后续继续执行。 **4. 恢复生成器:** - 当再次调用`__next__`方法时,解释器会从上次暂停的位置恢复执行生成器的帧。 ### PyGenObject 简化版结构 ``` typedef struct { PyObject_HEAD PyFrameObject *gi_frame; // 生成器的帧 PyObject *gi_code; // 生成器的代码对象 PyObject *gi_yieldfrom; // 用于 yield from 逻辑 int gi_running; // 表示生成器是否正在运行 PyObject *gi_exc_state; // 异常状态 } PyGenObject; ``` ### 示例:生成器的工作原理 为了更直观地理解生成器背后的机制,我们来看一个简单的示例,并在高层次上解释其工作原理: ``` def my_generator(): print("Start of generator") yield 1 print("After first yield") yield 2 print("After second yield") gen = my_generator() print(next(gen)) # 输出: Start of generator, 1 print(next(gen)) # 输出: After first yield, 2 print(next(gen)) # 输出: After second yield, StopIteration ``` 在上面的代码中,我们创建了一个简单的生成器函数my_generator。以下是内部机制的概述: **1. 创建生成器对象:** - 调用`my_generator()`时,Python解释器**创建一个生成器对象,但不会立即执行函数代码**。 **2. 首次调用next:** - 调用`next(gen)`时,解释器开始执行生成器的字节码,直到遇到第一个`yield`。 - 输出`Start of generator`,然后暂停执行,并返回1。 **3. 再次调用next:** - 调用`next(gen)`时,解释器继续执行生成器帧,从上次暂停的位置继续。 - 输出`After first yield`,然后遇到第二个`yield`,返回2。 **4. 再一次调用next:** - 调用`next(gen)`时,解释器再次恢复执行生成器帧。 - 输出`After second yield`,由于没有更多的`yield`语句,生成器结束,抛出`StopIteration`异常。 ### 查看CPython源码 如果你对深入理解CPython实现感兴趣,可以查看CPython的源码。以下是几个关键文件和函数: - Objects/genobject.c:定义了生成器对象的实现。 - ceval.c:包含字节码解释器的实现,处理生成器的运行逻辑。 您可以在CPython的GitHub库中找到这些文件和相关代码: [CPython GitHub Repository](https://github.com/python/cpython) ### 总结 生成器和yield背后的复杂实现涉及Python解释器内部的细节,对每个yield点保存与恢复生成器的执行状态。尽管底层实现十分复杂,通过查看源码和了解生成器的高层次工作原理,您可以更清楚地理解生成器的强大功能及其在懒加载和流式处理中提供的优势。
gaojian
2024年9月13日 14:45
分享文档
收藏文档
上一篇
下一篇
微信扫一扫
复制链接
手机扫一扫进行分享
复制链接
关于 MrDoc
觅思文档MrDoc
是
州的先生
开发并开源的在线文档系统,其适合作为个人和小型团队的云笔记、文档和知识库管理工具。
如果觅思文档给你或你的团队带来了帮助,欢迎对作者进行一些打赏捐助,这将有力支持作者持续投入精力更新和维护觅思文档,感谢你的捐助!
>>>捐助鸣谢列表
微信
支付宝
QQ
PayPal
Markdown文件
分享
链接
类型
密码
更新密码