python yield 生成器用法

1、yield 和 next(),send()方法

总结:可以把send()看成是next()的升级版。send()不仅能像next()一样触发生成器的一个迭代,还能传入一个值给 yield语句
看下面一个列子:

def func():
    y = 1
    while True:
        x = yield y          # 注意:此处的x只接收外部send发送过来的值,并不接收 yield y 对它的赋值。
        y += 1
        print('接收了x = {}'.format(x))


f = func()       # f是一个初始化好的生成器

# print('传入send(100):', f.send(100))  # 在生成器刚初始化时,不能用send()传入数据,否则会报错。 可以用send(None)。

print('第一次 next():', next(f))    #  生成器启动(激活生成器),代码停在‘x = yield y’这里,
                                   # 传入的值为None, next()相当于send(None),产生第一个yield值1。

print('第二次 next():', next(f))    #  next()函数触发生成器,从‘y+=1’开始运行,y变成了2,
                                   # 最后再次停在‘x=yield y’处,产生一个yield值2,因为没有接收到send值,所以x=None。

print('传入send(10):', f.send(10))  #  此时收到send(10), yield语句被赋值为10,即‘x=yield y =10’,⇨ ‘x=10’。
                                   # 但不影响yield自身产生的值,会接着运行‘y+=1‘,y变成3,
                                   # 所以仍会有一个‘next()’产生一个yield值3,再次停在‘x=yield y’处。
                                   # 此处敲黑板:send()带有next()功能。

print('第三次 next():', next(f))    #  next()函数触发生成器,从’y+=1‘开始运行,y变成了4,
                                   # 然后再次停在’x=yield y‘,产生一个yield值4,没有接收到send值,所以x=None。

f.close()                          #  close()关闭生成器.
#print('第四次 next():', next(f))   #  因为 close()关闭生成器,所以会产生StopIteration错误。

运行后的结果为:

第一次 next(): 1
# ======上面是第一次next的结果========

接收了x = None
第二次 next(): 2
# ======上面是第二次next的结果========

接收了x = 10
传入send(10): 3
# ======上面是send(10)的结果========

接收了x = None
第三次 next(): 4
# ======上面是第三次next的结果========

注:这里有一个 send( ) 知识点需要注意下

send() 有两个功能:
1、向当前 yield 迭代的“位置"发送值。
2、抛出下一个值,即执行next()。
例子如下:

def fun_yield():
    yield 1
    a = yield 2
    print(a)
    yield 3
    return 4

f = fun_yield()

print(next(f))  						   # 启动生成器,第一次迭代出 1, 代码停在此处。
print(f.send('这是在第二次迭代中传递的值'))   # 这时send传进去的值是赋给代码所停的yield位置处,即上面 1 的地方。
											# 再实现”next()“功能,迭代出 第二个值 2,然后代码停在 yield 2 的地方 。
											
print(f.send('这是在第三次迭代中传递的值'))    # 因为此时代码停在 yield 2 的地方,所以这时 send()进去的值 赋给了 a,相当于给a重新赋值了。
											 # 再实现 next() 功能,代码运行到下个 yield 处,所以会 print(a),再迭代出 3。

得到的结果为:

1
2
这是在第三次迭代中传递的值
3

这说明,虽然 a = yield 2 是在第二个迭代中的,但实际上 a 的值是第三次迭代时传进去的。
具体理解,可以看上面代码的注释。

2 yield from + return

def foo():    # 定义一个返回 0,1,2,3, 4 五个数字的生成器。
    n = 0
    while True:
        yield n
        n = n+1
        if n == 5:
            break
    return 1111     # 前5次的迭代不都会执行return,
    				# 等foo()中的元素迭代完后,再一次迭代会报错: “StopIteration”,并返回一个 1111 的值。

def func():
    a = yield from foo()    					   # 调用 foo()生成器。
    print('foo() 最后的返回值 a = {}'.format(a))    # 当foo()生成器的元素全部迭代完后,再次调用 next(),就执行这句代码。
    yield 2222								       # 调用 next()执行上面这句代码后,马上执行这句代码,yield 出 2222。


f = func()

for i in range(6):
	print(next(f))
# 迭代6次,前面5次从 foo()中取出,
# 第6次迭代时,foo()产生一个StopIteration错误,并返回一个值 1111 给func()中的a
# 然后 func()自身 yield 出 2222 给第六次的迭代结果。
    

再看一个例子:

def func_square():
    print("调用平方计算函数")
    num = yield "请输入需要计算的数字"          # num 接收 send 发送来的数字。
    n = 1
    while True:
        print(f"第{n}次计算{num}的平方")
        num = yield pow(num, 2)
        n += 1
        if num == 0:
            return "hello world"


def main():
    print("开始执行main函数……")
    m = yield from func_square()
    print(m)


do = main()
print(next(do))
print(do.send(10))
print(do.send(20))
# do.send(0)
try:
    do.send(0)
except StopIteration:
    pass

执行结果:

开始执行main函数……
调用平方计算函数
请输入需要计算的数字
第1次计算10的平方
100
第2次计算20的平方
400
hello world
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值