Python生成器与yield关键字深度解析:__next__与send机制详解

凌晨两点半
凌晨两点半
发布时间:2026-10-12 | 2人浏览过
原创

本文深入解析Python中yield关键字构建生成器的核心机制。详细对比__next__与send函数的执行流程与返回值差异,阐述send函数如何向生成器内部传递值。通过代码示例说明生成器的迭代逻辑、赋值语句执行时机,并指出超出循环范围调用__next__会触发StopIteration异常,帮助开发者高效利用生成器节省内存资源。

前言

Python中提供了一种高效的语法结构——生成器,其核心依赖于yield关键字。合理使用生成器能够显著优化系统资源消耗,避免不必要的内存占用问题。

代码示例

def fun():
for i in range(20):
 x=yield i
 print('good',x)
if __name__ == '__main__':
a=fun()
a.__next__()
x=a.send(5)
print(x)

以下代码虽短,却清晰展示了yield关键字的核心功能:逐个产出值。示例中获取了两个生成器产生的数值,分别为0和1,分别通过next函数和send()函数获取,关于这两个函数的具体区别将在后文详细展开。

关于__next__函数,此处先作简要说明。我们可以利用__next__()方法持续获取符合fun函数生成规则的数值,直至迭代至19为止。相关代码如下:

def fun():
for i in range(20):
 x=yield i
if __name__ == '__main__':
for x in fun():
 print(x)

上述代码的运行效果与以下代码完全一致:

if __name__ == '__main__':
for i in range(20):
 x=yield i

虽然for...in循环是调用生成器的基础用法,但仅掌握此用法意义有限。生成器中更为关键的是send和__next__这两个函数,下文将对它们进行详细阐述。

send函数详解

此处特别强调send函数,因为其机制不如__next__直观。__next__函数的逻辑较为清晰:从上一个终止点开始执行,直到遇到下一个yield语句结束,其返回值即为yield表达式的值。

例如在初始的那段代码里:

def fun():
for i in range(20):
 x=yield i
 print('good',x)

第一次调用__next__函数时,程序从fun函数的起点开始执行,在yield处暂停。需要注意的是,此时赋值语句尚未调用,此处的yield i与return在行为上类似。

然而,第二次调用__next__函数时,程序会直接从上一个yield的结束点继续执行。这意味着先执行赋值语句,然后输出字符串,进入下一个循环,直到遇到下一个yield或生成器结束。

再次观察初始代码,可以发现第二次调用时并未使用__next__函数,而是使用了send()函数。这里需要注意,send()函数的用法与__next__函数存在显著差异。send()函数只能从yield之后开始执行,直到下一个yield结束。这意味着第一次调用必须使用__next__函数来启动生成器。

send()函数最重要的作用在于它能够为yield对应的赋值语句提供值,例如上面那一段代码中的

x=yield i

如果调用__next()__函数,那么x的值为None。但是如果调用send(5),那么x的值即为5。除了上述两个显著特征外,send和next在行为上并无其他区别,send函数同样会返回yield表达式对应的值。

next函数调用次数可能受限

需要特别注意的是,尽管生成器具有惰性求值特性,但next函数的调用次数可能是有限的。如下面这段代码所示:

def fun():
for i in range(20):
 x=yield i
 print('good',x)
if __name__ == '__main__':
a=fun()
for i in range(30):
 x=a.__next__()
 print(x)

生成器内部的函数仅循环了20次,但如果next函数被调用了30次,此时将会触发StopIteration异常。

总结

以上所述是小编给大家介绍的Python中的yield关键字,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对本站网站的支持!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表