Thinking in yield
为了更深入的了解生成器,还是先介绍下生成器有的特性和特点吧:
- 可以迭代(恩,这个特性是废话,从名字都可以看出来,但是这的确是生成器最基本的一个特性)
- 通过调用next函数或者send函数(其实next() = send(None) ),会执行到yield语句,就会被冻结,冻结后就返回它的caller;直至调用下次send函数从上次冻结点接着执行
- 当生成器对象引用计数为0被回收时,如果发现生成器对象仍然被冻结,就会调用close函数,close函数的作用就是抛出一个GeneratorExit的异常
- 生成器只能被迭代一次(有点惊讶?我看源码的时候,发现这个的时候也有点)
那generator是如何实现的呢?看了源码其实很简单,在初始化一个生成器对象,都需要一个参数: PyFrameObject * f。这个f就是生成器函数的栈帧,当函数被冻结时,记录这个栈帧的栈点stacktop 以及虚拟机字节码位置f_lasti。下次执行的时候直接从这个字节码位置和栈点执行。一切很简单吧!
一切谜底都要从python源码Python/ceval.c中的PyEval_EvalFrameEx开始,初始化代码:
- /* An explanation is in order for the next line.
- f->f_lasti now refers to the index of the last instruction
- executed. You might think this was obvious from the name, but
- this wasn't always true before 2.3! PyFrame_New now sets
- f->f_lasti to -1 (i.e. the index *before* the first instruction)
- and YIELD_VALUE doesn't fiddle with f_lasti any more. So this
- does work. Promise. */
- next_instr = first_instr + f->f_lasti + 1;
- stack_pointer = f->f_stacktop;
- assert(stack_pointer != NULL);
- f->f_stacktop = NULL;
- /* remains NULL unless yield suspends frame */
那yield或者说生成器都有哪些应用呢:
- 生成迭代器(靠,又是废话)
- 与with_statement结合使用
- 著名的”Trampoline in python”
- 轻量级任务
- 其他……
Resouces & References:
- The yield statement
- Coroutines via Enhanced Generators
- The with statement
- Tramoplining in python(这个地方请看评论,我觉得评论比文章更为精彩)
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。