为什么Python的yield在被调用的子函数中不生效且无运行报错?
问题原因解释
核心逻辑:带yield的函数是生成器函数,不是普通函数
Python对包含yield关键字的函数有特殊处理:
- 只要函数定义里出现
yield,它就不再是普通函数,会被标记为生成器函数 - 直接调用生成器函数不会执行函数内部的任何代码,只会返回一个生成器对象,你必须主动迭代这个对象(比如用
for循环遍历、调用next()方法),才会执行生成器内部的代码,直到碰到下一个yield语句暂停。
你写的代码的执行逻辑
你在fn里直接写fn2()这行代码,本质只是创建了一个fn2对应的生成器对象,没有做任何迭代操作,所以fn2里的yield "you"根本不会被外层的for循环捕获,自然遍历不到这个值。
另外你描述的两种测试结果大概率是记反了,符合Python实际执行规则的现象是:
- 保留
fn2里的yield语句:fn2是生成器函数,调用fn2()仅返回生成器对象,不执行内部代码,最终输出为:hi there - 注释掉
fn2里的yield语句:fn2没有yield,变成普通函数,调用fn2()会直接执行内部的print("blah"),最终输出为:hi blah there
两种情况都不会报错,因为创建生成器对象本身就是合法的Python语法,你只是没有使用它而已,解释器不会对未使用的对象抛出警告。
解决方案
如果要让父生成器自动迭代子生成器,把所有子生成器的yield值都向上返回给外层迭代,使用Python 3.3及以上版本支持的yield from语法即可,修改后的代码如下:
def fn2(): print("blah") yield "you" def fn(): yield "hi" yield from fn2() # 替换原来的直接调用fn2() yield "there" for a in fn(): print('{}'.format(a))
修改后的运行输出为:
hi blah you there
完全符合你预期的效果。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

