我是Python和编程方面的新手。对于新的程序员来说,生成器太复杂了,无法理解。下面是我对Python中生成器函数的理论:
yield
语句的函数都将返回生成器对象。.next
方法时,Python都提取函数的状态,当它找到另一个deletes语句时,它将再次绑定该状态并删除先前的状态:示例:
[
[state1] # Stack contains states and states contain info about the function
[state2] # State1 will be deleted when python finds the other yield?
]
当然,这可能是地球上最愚蠢的理论,但请原谅我,我只是一个新的编码词。
我的问题:
yield
语句是否将状态添加到堆栈中?.next
方法提取每个状态,例如,Python会用索引状态自动调用函数吗?发布于 2014-08-10 21:14:45
任何包含产额语句的函数都将返回生成器对象。
这是正确的。包含yield
的函数的返回值是生成器对象。生成器对象是一个迭代器,其中每次迭代都返回支持生成器的代码中的yield
编辑的值。
生成器对象是包含状态的堆栈。
生成器对象包含指向当前执行框架的指针,以及用于维护生成器状态的大量其他东西。执行框架包含生成器中代码的调用堆栈。
每次我调用
.next
方法时,Python都会提取函数的状态,当它找到另一条收益率语句时,它会再次绑定状态并删除先前的状态
说大也大吧。当您调用next(gen_object)
时,Python 评估当前执行框架。
gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) { // This is called when you call next(gen_object)
PyFrameObject *f = gen->gi_frame;
...
gen->gi_running = 1;
result = PyEval_EvalFrameEx(f, exc); // This evaluates the current frame
gen->gi_running = 0;
PyEval_EvalFrame
是最高级别的函数用于解释Python字节码。
PyObject PyEval_EvalFrameEx(PyFrameObject f,int行标志) 这是Python解释的主要、未修饰的函数。从字面上说,它有2000行长。执行与执行框架f相关联的代码对象,解释字节码并根据需要执行调用。附加的throw频标志参数可以被忽略-如果为真,则会立即抛出异常;这用于生成器对象的抛出()方法。
它知道当它在计算字节码时碰到yield
时,它应该是返回被释放给调用方的值。。
TARGET(YIELD_VALUE) {
retval = POP();
f->f_stacktop = stack_pointer;
why = WHY_YIELD;
goto fast_yield;
}
当您放弃时,框架的值堆栈的当前值将被维护(通过f->f_stacktop = stack_pointer
),这样我们就可以在再次调用next
时恢复到中断的位置。所有非生成器函数在完成评估后将f_stacktop
设置为NULL
。因此,当您在生成器对象上再次调用next
时,将使用与前面相同的帧指针再次调用PyEval_ExvalFrameEx
。指针的状态将与前一次生成时的状态完全相同,因此从那时起将继续执行。基本上,框架的当前状态是“冻结”的。这在引入发电机的PEP中有描述。
如果遇到屈服语句,则会冻结函数的状态,并将得到的值返回给.next()的调用方。所谓“冻结”,指的是保留所有本地状态,包括当前局部变量绑定、指令指针和内部计算堆栈:保存了足够的信息,以便在下次调用.next()时,函数完全可以继续进行,就好像产量语句只是另一个外部调用一样。
下面是生成器对象维护的大部分状态(直接从其头文件中获取):
typedef struct {
PyObject_HEAD
/* The gi_ prefix is intended to remind of generator-iterator. */
/* Note: gi_frame can be NULL if the generator is "finished" */
struct _frame *gi_frame;
/* True if generator is being executed. */
char gi_running;
/* The code object backing the generator */
PyObject *gi_code;
/* List of weak reference. */
PyObject *gi_weakreflist;
/* Name of the generator. */
PyObject *gi_name;
/* Qualified name of the generator. */
PyObject *gi_qualname;
} PyGenObject;
gi_frame
是指向当前执行框架的指针。
请注意,所有这些都是特定于CPython实现的。PyPy/Jython/等很可能以完全不同的方式实现生成器。我鼓励您通过读取生成器对象的源了解更多关于CPython实现的信息。
https://stackoverflow.com/questions/25232350
复制相似问题