Python yield与实现
admin
2023-07-31 00:46:30
0

Python yield与实现

yield的功能类似于return,但是不同之处在于它返回的是生成器

生成器

生成器是通过一个或多个yield表达式构成的函数,每一个生成器都是一个迭代器(但是迭代器不一定是生成器)。

如果一个函数包含yield关键字,这个函数就会变为一个生成器。

生成器并不会一次返回所有结果,而是每次遇到yield关键字后返回相应结果,并保留函数当前的运行状态,等待下一次的调用。

由于生成器也是一个迭代器,那么它就应该支持next方法来获取下一个值。

基本操作

1234567 # 通过`yield`来创建生成器def func():   for i in xrange(10);        yield i # 通过列表来创建生成器[i for i in xrange(10)]

12345678910111213141516 # 调用如下>>> f = func()>>> f # 此时生成器还没有运行<generator object func at 0x7fe01a853820>>>> f.next() # 当i=0时,遇到yield关键字,直接返回0>>> f.next() # 继续上一次执行的位置,进入下一层循环1...>>> f.next()9>>> f.next() # 当执行完最后一次循环后,结束yield语句,生成StopIteration异常Traceback (most recent call last):  File \”\”, line 1, in <module>StopIteration>>>

除了next函数,生成器还支持send函数。该函数可以向生成器传递参数。

12345678910111213 >>> def func():...     n = 0...     while 1:...         n = yield n #可以通过send函数向n赋值... >>> f = func()>>> f.next() # 默认情况下n为00>>> f.send(1) #n赋值11>>> f.send(2)2>>>

应用

最经典的例子,生成无限序列。

常规的解决方法是,生成一个满足要求的很大的列表,这个列表需要保存在内存中,很明显内存限制了这个问题。

1234 def get_primes(start):    for element in magical_infinite_range(start):        if is_prime(element):            return element

如果使用生成器就不需要返回整个列表,每次都只是返回一个数据,避免了内存的限制问题。

12345 def get_primes(number):    while True:        if is_prime(number):            yield number        number += 1

生成器源码分析

生成器的源码在Objects/genobject.c

调用栈

在解释生成器之前,需要讲解一下Python虚拟机的调用原理。

Python虚拟机有一个栈帧的调用栈,其中栈帧的是PyFrameObject,位于Include/frameobject.h

1...>>> f.next()9>>> f.next() # 当执行完最后一次循环后,结束yield语句,生成StopIteration异常Traceback (most recent call last):  File \”\”, line 1, in <module>StopIteration>>>

除了next函数,生成器还支持send函数。该函数可以向生成器传递参数。

12345678910111213 >>> def func():...     n = 0...     while 1:...         n = yield n #可以通过send函数向n赋值... >>> f = func()>>> f.next() # 默认情况下n为00>>> f.send(1) #n赋值11>>> f.send(2)2>>>

应用

最经典的例子,生成无限序列。

常规的解决方法是,生成一个满足要求的很大的列表,这个列表需要保存在内存中,很明显内存限制了这个问题。

1234 def get_primes(start):    for element in magical_infinite_range(start):        if is_prime(element):            return element

如果使用生成器就不需要返回整个列表,每次都只是返回一个数据,避免了内存的限制问题。

12345 def get_primes(number):    while True:        if is_prime(number):            yield number        number += 1

生成器源码分析

生成器的源码在Objects/genobject.c

调用栈

在解释生成器之前,需要讲解一下Python虚拟机的调用原理。

Python虚拟机有一个栈帧的调用栈,其中栈帧的是PyFrameObject,位于Include/frameobject.h

1234567891011121314151617181920212223242526272829303132333435 typedef struct _frame {    PyObject_VAR_HEAD    struct _frame *f_back;  /* previous frame, or NULL */    PyCodeObject *f_code;   /* code segment */    PyObject *f_builtins;   /* builtin symbol table (PyDictObject) */    PyObject *f_globals;    /* global symbol table (PyDictObject) */    PyObject *f_locals;     /* local symbol table (any mapping) */    PyObject **f_valuestack;    /* points after the last local */    /* Next free slot in f_valuestack.  Frame creation sets to f_valuestack.       Frame evaluation usually NULLs it, but a frame that yields sets it       to the current stack top. */    PyObject **f_stacktop;    PyObject *f_trace;      /* Trace function */     p;  /* If an exception is raised in this frame, the next three are used to     * record the exception info (if any) originally in the thread state.  See     * comments before set_exc_info() — it\’s not obvious.     * Invariant:  if _type is NULL, then so are _value and _traceback.     * Desired invariant:  all three are NULL, or all three are non-NULL.  That     * one isn\’t currently true, but \”should be\”.     */    PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;     PyThreadState *f_tstate;    int f_lasti;        /* Last instruction if called */    /* Call PyFrame_GetLineNumber() instead of reading this field       directly.  As of 2.3 f_lineno is only valid when tracing is

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...