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