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

Python generator send()方法异常输出的运行机制咨询

Python生成器send()方法跳值问题解析

问题复现

初始版本的3的倍数生成器运行正常,代码如下:

def MultipleOfThree():
    num  = 1
    while True:
        if num % 3 == 0:
           yield num
        num += 1

#test
iter = MultipleOfThree()

for m3 in iter:    
    print(m3)

运行后会按顺序输出3、6、9、12、15……所有3的正整数倍。
添加send逻辑修改代码后,输出出现跳数,仅输出3、9、15、21、27,间隔为6,跳过了6、12、18等本该输出的数值,修改后代码如下:

def MultipleOfThree():
    num  = 1

    while True:
        if num % 3 == 0:
            i = yield num   
            if i is not None:
                num = i
        num += 1

#test
iter = MultipleOfThree()

for m3 in iter:    
    print(m3)
    iter.send(m3) #for simplicity send the m3 itself

核心运行规则

出现这个问题的本质是没搞懂生成器的两个基础运行逻辑:

  • 所有触发生成器运行的操作(包括for循环隐式调用next()、手动调用next()、调用send()),都会让生成器从当前暂停的yield位置继续向下执行,直到碰到下一个yield才会暂停,同时把yield关键字后面的值作为本次调用的返回值传出。
  • send(x)的作用等价于「给当前暂停位置的yield表达式传返回值x」+「执行一次next()让生成器继续跑到下一个yield点」,也就是说 调用一次send,就会消耗掉生成器的一个yield输出。

逐行执行流程拆解

顺着代码跑一遍流程就能看到跳数的原因:

  1. 初始化生成器iter = MultipleOfThree()时,生成器停在函数入口,还没执行任何代码。
  2. for循环第一次隐式调用next(iter)启动生成器:num从1开始自增,直到num=3时触发i = yield num,把3传出给for循环,生成器暂停在这行,for循环拿到3赋值给m3,打印3。
  3. 接下来执行iter.send(3):
    • 首先把传入的3赋值给当前暂停位置的变量i,因为i不是None,执行num = i把num设为3;
    • 继续向下执行num += 1,num变成4;
    • 回到while循环继续自增,直到num=6时再次碰到i = yield num,把6传出——这个6是send()调用的返回值,你没有接收也没有打印,直接被丢弃了,生成器暂停在返回6的yield位置。
  4. for循环进入下一轮,隐式调用next(iter):
    • 生成器从返回6的yield位置继续跑,因为是next()调用,没有传入值,所以当前yield表达式的返回值i为None,不触发num赋值逻辑;
    • 向下执行num +=1,num从6变成7,继续自增直到num=9时碰到yield,把9传出给for循环,打印9。
  5. 之后重复步骤3-4的逻辑:send(9)会让生成器跑到num=12时返回12并丢弃,下一轮for循环的next会跑到num=15打印,最终就出现了间隔6输出的现象。

验证与修正

你可以把send的返回值打印出来,就能看到被跳过的数值:

iter = MultipleOfThree()
for m3 in iter:    
    print("for循环打印值:", m3)
    skip_val = iter.send(m3)
    print("send调用返回的被跳过值:", skip_val)
    if m3 > 30:
        break

运行后就能看到完整的3的倍数序列,只是一半被for循环拿到,一半被send调用拿到。
如果要正常迭代同时使用send,不要用for循环隐式迭代,手动控制生成器运行即可,注意 刚初始化的生成器必须先调用一次next()启动到第一个yield位置,才能传入非None的send值,否则会抛出类型错误:

iter = MultipleOfThree()
current = next(iter)
print(current)
while current < 30:
    current = iter.send(current)
    print(current)

内容的提问来源于stack exchange,提问作者Tanzer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:45:31