You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python生成器发送数据出现None值问题排查与解决

问题根源:生成器内的双重yield导致执行流程错位

你的spam()生成器里有两个独立的yield语句,这直接导致每次send()调用的执行流程出现了交替的“有效处理”和“无意义返回None”的情况,我一步步拆解给你看:

逐行梳理执行流程:

  1. 初始化生成器:s = spam(),此时生成器还未启动,只是个对象。
  2. 第一次启动生成器:next(s),生成器执行到received = yield处暂停——这个yield是用来接收外部值的,本身没有产出任何内容,所以next()返回None(你没打印这个值)。
  3. 第一次send("Bob"):
    • 把"Bob"传递给暂停的received = yield,received被赋值为"Bob"。
    • 执行print语句,打印收到Bob的消息。
    • 执行yield received,产出"Bob",生成器暂停在这里。
    • send("Bob")的返回值就是这个产出的"Bob",所以你看到打印了"Bob"。
  4. 第二次send("Nancy"):
    • 生成器从yield received的位置恢复,你发送的"Nancy"会被传递给这个yield表达式,但这个yield没有被赋值给任何变量,所以"Nancy"直接被丢弃了。
    • 生成器进入下一次while循环,执行到received = yield处暂停——这个yield同样没有产出内容,所以send("Nancy")的返回值是None,这就是你看到的第一个None。
    • 注意:此时received根本没被赋值为"Nancy",因为生成器停在了received = yield的赋值步骤之前!
  5. 第三次send("Daniela"):
    • 把"Daniela"传递给暂停的received = yield,received被赋值为"Daniela"。
    • 执行print语句,打印收到Daniela的消息。
    • 执行yield received,产出"Daniela",生成器暂停。
    • send("Daniela")返回"Daniela",所以打印"Daniela"。
  6. 第四次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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:11:38