Python生成器发送数据出现None值问题排查与解决
问题根源:生成器内的双重yield导致执行流程错位
你的spam()生成器里有两个独立的yield语句,这直接导致每次send()调用的执行流程出现了交替的“有效处理”和“无意义返回None”的情况,我一步步拆解给你看:
逐行梳理执行流程:
- 初始化生成器:
s = spam(),此时生成器还未启动,只是个对象。 - 第一次启动生成器:
next(s),生成器执行到received = yield处暂停——这个yield是用来接收外部值的,本身没有产出任何内容,所以next()返回None(你没打印这个值)。 - 第一次
send("Bob"):- 把"Bob"传递给暂停的
received = yield,received被赋值为"Bob"。 - 执行
print语句,打印收到Bob的消息。 - 执行
yield received,产出"Bob",生成器暂停在这里。 send("Bob")的返回值就是这个产出的"Bob",所以你看到打印了"Bob"。
- 把"Bob"传递给暂停的
- 第二次
send("Nancy"):- 生成器从
yield received的位置恢复,你发送的"Nancy"会被传递给这个yield表达式,但这个yield没有被赋值给任何变量,所以"Nancy"直接被丢弃了。 - 生成器进入下一次
while循环,执行到received = yield处暂停——这个yield同样没有产出内容,所以send("Nancy")的返回值是None,这就是你看到的第一个None。 - 注意:此时
received根本没被赋值为"Nancy",因为生成器停在了received = yield的赋值步骤之前!
- 生成器从
- 第三次
send("Daniela"):- 把"Daniela"传递给暂停的
received = yield,received被赋值为"Daniela"。 - 执行
print语句,打印收到Daniela的消息。 - 执行
yield received,产出"Daniela",生成器暂停。 send("Daniela")返回"Daniela",所以打印"Daniela"。
- 把"Daniela"传递给暂停的
- 第四次
send("Martin"):- 生成器从
yield received恢复,丢弃"Martin",进入下一次循环到received = yield暂停。 send("Martin")返回None,打印None。
- 生成器从
这就是为什么你会看到交替出现的正常名字和None——每两次send()中,只有一次是真正接收并产出值,另一次完全是无效的流程跳转。
解决方法:简化生成器的yield逻辑
根据你的代码意图(接收值→打印→返回该值),我们可以把两个yield合并成一个,让每个循环周期只完成一次“接收-处理-产出”的完整流程:
修改后的代码:
def spam(): received = None while True: # 核心:这个yield同时完成「产出当前值」和「接收新值赋值给received」的操作 received = yield received print("Message received from generator function:", received) if __name__ == "__main__": s = spam() print(s) next(s) # 启动生成器,走到yield处(返回初始的None,我们可以忽略) names = ["Bob", "Nancy", "Daniela", "Martin"] for name in names: print(s.send(name))
运行效果:
<generator object spam at 0x10873aa20> Message received from generator function: Bob Bob Message received from generator function: Nancy Nancy Message received from generator function: Daniela Daniela Message received from generator function: Martin Martin
如果你的需求只是接收值并打印,不需要返回值,那可以进一步简化,去掉产出逻辑:
def spam(): while True: received = yield print("Message received from generator function:", received) if __name__ == "__main__": s = spam() next(s) names = ["Bob", "Nancy", "Daniela", "Martin"] for name in names: s.send(name) # 不需要打印send的返回值,自然就不会出现None
内容的提问来源于stack exchange,提问作者Subhayan Bhattacharya
相关产品推荐
相关产品推荐

