Logo

郎哥编程

生成器类型与yield表达式

2020-12-29 150

生成器类型使用英文单词generator表示,generator的汉译就是发生器的意思,生成器类型也属于迭代器类型。

一个生成器类型的对象由函数来创建,不过这个函数有点特殊,在函数内部包含一个 yield 表达式,该表达式会产生一系列值提供给 for循环使用,或者通过 next() 函数逐一获取,该函数也称为生成器函数,当一个生成器函数被调用时,它会返回一个生成器类型的对象。

认识yield 表达式

yield 表达式的语法如下:

yield [expression_list | from expression]

yield是Python的关键字,expression_list是表达式列表,每个表达式用英文逗号分隔,from expression会将所提供的表达式视为一个子迭代器。 这个子迭代器产生的所有值都直接被传递给当前生成器函数的调用者。

expression_list和from expression只能二选一。

例如下面的代码定义了一个生成器函数:

def fn(n):
  for i in range(n):
    yield i*2

生成器函数和普通函数的定义完全相同,不同点是在函数内部使用了yield表达式。

生成器函数的执行过程

当一个生成器函数被调用的时候,它返回一个迭代器,称为生成器(生成器类型对象)。然后这个生成器来控制生成器函数的执行。当这个生成器的某一个方法被调用的时候,生成器函数开始执行。

生成器函数会一直执行到第一个 yield 表达式,此时生成器函数的执行会被挂起(函数停止执行),并给生成器的调用者返回 expression_list 的值。

生成器函数挂起后,Python解释器会把该函数所有的局部状态都保留下来,包括函数执行的上下文环境。当生成器的某一个方法被调用时,该函数会继续执行yield 表达式后面的语句。

 生成器类型的方法

前文中提到了生成器的某一个方法,该生成器是generator类型,generator类型提供了下面的方法。

方法声明:

__next__()

该方法开始一个生成器函数的执行或是从上次执行的 yield 表达式位置恢复执行。 当一个生成器函数通过 __next__() 方法恢复执行时,当前的 yield 表达式总是取值为 None。 随后会继续执行到下一个 yield 表达式,其 expression_list 的值会返回给 __next__() 的调用者。如果生成器没有产生下一个值就退出,则将引发 StopIteration 异常。

此方法通常是隐式地调用,例如通过 for 循环或是内置的 next() 函数。

方法声明:

send(value)

该方法向生成器函数发送值value,并恢复生成器函数的执行。参数value将成为当前 yield 表达式的结果。该方法会返回生成器函数所产生的下一个值,或者如果生成器函数没有产生下一个值就退出,则会引发 StopIteration异常。

当调用 send(value) 方法来启动生成器函数时,它必须以 None 作为调用参数,因为这时没有可以接收值的 yield 表达式。

方法声明:

throw(type[, value[, traceback]])

该方法在生成器函数挂起的位置引发 type 类型的异常,并返回该生成器函数所产生的下一个值。 如果生成器没有产生下一个值就退出,则将引发 StopIteration 异常。

方法声明:

close()

该方法在生成器函数挂起的位置引发GeneratorExit异常,并关闭生成器。

生成器案例

创建一个从序列对象随机选取元素的随机生成器。

# 导入random模块
import random
# 定义生成器函数
def randGen(a):
  # 循环条件为列表对象a的长度大于0
  while len(a) > 0:
    # 使用yield表达式随机返回列表对象的元素
    # 列表对象的pop方法返回元素的同时会移除该元素
    yield a.pop(random.randint(0,len(a)-1))
 
# 创建颜色列表对象
color = ["yellow","white","black","red","blue","green"]
# 调用生成器函数随机输出颜色
for item in randGen(color):
    print(item)

函数randGen是随机生成器,它随机返回颜色列表对象color的元素,同时从color对象移除该元素。

randGen函数第一次被调用时会返回一个生成器(生成器类型的对象,该类型属于迭代器类型),因此for循环进入迭代模式,生成器控制randGen函数的执行。

randGen函数执行到yield表达式,函数返回随机选取的color列表对象元素给生成器,此时函数被挂起,停止执行。for循环进入下一轮迭代,会调用生成器的_next_()方法获取下一个元素,生成器会再次启动生成器函数,生成器函数会从上次yield表达式后面的语句开始执行,若yield表达式后面没有语句,则进入下一轮的while循环,直至循环条件不满足时,生成器函数结束运行。

生成器函数结束运行后,生成器无法迭代获取下一个元素,因此for循环结束迭代。

上机操作

编写一个生成器,生成器返回给定元素在序列对象的索引。

序列对象:

s = [9,12,89,22,21,36,90,92,91]

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论