说明
《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
在Python中,yield 是一个关键字,用于定义生成器函数。生成器函数是一种特殊的函数,它可以暂停执行并保存当前状态,以便在下次调用时恢复执行。这使得生成器函数可以按需生成一系列值,而不需要一次性生成所有值,从而节省内存。yield 表达式用于产生一个值,并暂停生成器的执行,将该值返回给调用者。下次调用生成器时,执行将从上次暂停的地方继续进行。
以下是一个简单的例子,演示了 yield 的使用:
def simple_generator():
yield 1
yield 2
yield 3
# 创建生成器对象
gen = simple_generator()
# 调用生成器的 __next__ 方法获取值
print(next(gen)) # 输出: 1
print(next(gen)) # 输出: 2
print(next(gen)) # 输出: 3
# 如果再次调用 __next__,会引发 StopIteration 异常,表示生成器没有更多的值
# print(next(gen)) # 引发 StopIteration 异常
生成器函数可以包含更复杂的逻辑,允许在每次调用时生成不同的值。生成器常用于处理大量数据或无限序列,因为它们允许逐个生成值,而不必将所有值存储在内存中。
值得注意的是,生成器函数中的 yield 不仅仅是返回值的作用,它还可以用于接收调用者传递的值,从而实现双向通信。这是通过调用生成器的 send 方法实现的。但是,这方面的细节可能较为复杂,需要更深入的了解。
关于 yield 的讲解,参见 Python 生成器类型 的内容。
yield 语句在语义上等同于 yield 表达式。 yield 语句可用来省略在使用等效的 yield 表达式语句时所必须的圆括号。 例如,以下 yield 语句:
yield <expr>
yield from <expr>
等同于以下 yield 表达式语句
(yield <expr>)
(yield from <expr>)
yield 表达式和语句仅在定义 generator 函数时使用,并且仅被用于生成器函数的函数体内部。 在函数定义中使用 yield 就足以使得该定义创建的是生成器函数而非普通函数。
详细语法如下:
yield_atom ::= "(" yield_expression ")"
yield_expression ::= "yield" [expression_list | "from" expression]
yield 表达式在定义 generator 函数或 asynchronous generator 函数时才会用到因此只能在函数定义的内部使用。 在一个函数体内使用 yield 表达式会使这个函数变成一个生成器函数,而在一个 async def 函数的内部使用它则会让这个协程函数变成一个异步生成器函数。 例如:
def gen(): # defines a generator function
yield 123
async def agen(): # defines an asynchronous generator function
yield 123
由于它们会对外层作用域造成附带影响,yield 表达式不被允许作为用于实现推导式和生成器表达式的隐式定义作用域的一部分。
在 3.8 版更改: 禁止在实现推导式和生成器表达式的隐式嵌套作用域中使用 yield 表达式。
下面是对生成器函数的描述,异步生成器函数会在 异步生成器函数 一节中单独介绍。
当一个生成器函数被调用时,它返回一个名为生成器的迭代器。 然后这个生成器将控制生成器函数的执行。 执行过程会在这个生成器的某个方法被调用时开始。 这时,函数会执行到第一个 yield 表达式,在这里它将再次被挂起,向生成器的调用方返回 expression_list 的值,或者如果 expression_list 被省略则返回 None。 这里所谓的挂起,就是说所有局部状态都会被保留下来,包括局部变量的当前绑定、指令指针、内部求值栈和任何异常处理等等。 当通过调用生成器的某个方法恢复执行时,这个函数的运行就与 yield 表达式只是一个外部调用的情况完全一样。 恢复之后 yield 表达式的值取决于恢复执行所调用的方法。 如果是用 __next__()
(通常是通过 for 或 next() 内置函数) 则结果为 None。 在其他情况下,如果是用 send(),则结果将为传给该方法的值。
所有这些使生成器函数与协程非常相似;它们 yield 多次,它们具有多个入口点,并且它们的执行可以被挂起。唯一的区别是生成器函数不能控制在它在 yield 后交给哪里继续执行;控制权总是转移到生成器的调用者。
在 try 结构中的任何位置都允许yield表达式。如果生成器在(因为引用计数到零或是因为被垃圾回收)销毁之前没有恢复执行,将调用生成器-迭代器的 close() 方法. close 方法允许任何挂起的 finally 子句执行。
当使用 yield from <expr>
时,所提供的表达式必须是一个可迭代对象。 迭代该可迭代对象所产生的值会被直接传递给当前生成器方法的调用者。 任何通过 send() 传入的值以及任何通过 throw()
传入的异常如果有适当的方法则会被传给下层迭代器。 如果不是这种情况,那么 send() 将引发 AttributeError 或 TypeError,而 throw() 将立即引发所转入的异常。
当下层迭代器完成时,被引发的 StopIteration 实例的 value 属性会成为 yield 表达式的值。 它可以在引发 StopIteration 时被显式地设置,也可以在子迭代器是一个生成器时自动地设置(通过从子生成器返回一个值)。
在 3.3 版更改: 添加 yield from <expr>
以委托控制流给一个子迭代器。
当yield表达式是赋值语句右侧的唯一表达式时,括号可以省略。
更新时间:Dec. 23, 2023, 10:26 a.m. 标签:python 习题 数字