yield 及 协程
yield 的用法很像 return,都是提供一个返回值,但是 yield 和 return 的最大区别在于:
- return 一旦返回,则代码段执行结束
- yield 代码段执行不会结束,只是中断;当被唤醒后继续在中断位置执行
yield 特性
- yield 则当前的函数会变成生成器
- yield 在返回值以后,会交出 CPU 的使用权,代码段并没有直接结束,而是在此处中断
- 当调用
send()
或next()
方法后,yield 可以从之前中断的地方继续执行。
简单示例
def test_yield(n):
index = 0
while index < n:
yield index
index += 1
mm = test_yield(5)
print(next(mm))
print(next(mm))
print(next(mm))
#--------输出-----
0
1
2
Process finished with exit code 0
执行顺序如下
- 创建生成器对象 , 实例化生成器 mm = test_yield(5)
- 协程还未激活(GEN_CREATED 状态)调用
next(mm)
方法激活协程 - 遇到 yield 程序中断,返回当前 index 的值 0, 程序中断 (也可以不返回
yield
返回给程序的是None
)。 - 再次调用 next(mm) 方法,程序被唤醒,程序继续运行,yield 返回 index 的值 1,程序中断
- 再次调用 next(mm) 方法,程序被唤醒,程序继续运行,yield 返回 index 的值 2,程序中断
- 还可以继续调用,如此继续下去,直到 test_yield(5) 中 index < 5 时,程序结束。
生成器对象
下面生成一个斐波那契数列:
def findex(n):
index = 0
a = 0
b = 1
while index < n:
yield b
a,b = b, a+b
a=b; b=a+b
index += 1
print(type(findex(10)))
print(findex(10))
# --- 输出 ---打印出来的结果是一个生成器对象--
<class 'generator'>
<generator object fib at 0x00000205B8D9CAC0>
next() 方法使用
语法 :
next(实例化的生成器)
引用 简单示例 程序,中已经讲解了
- 当协程处于未激活状态时,
next(mm)
激活协程 - 协程挂起状态时,
next(mm)
唤醒程序
python 新版本中,不再提供 mm.next() 方法,即 <实例化生成器>.next() 方法。
send() 方法使用
使用send()方法允许我们向生成器中传值
语法 :
生成器对象.send(None)
生成器对象.send(传值)
引用 简单示例 程序,中已经讲解了
- 当协程处于未激活状态时,
mm.send(None)
激活协程
传值及激活协程,示例如下
def test2_yield(n):
index = 0
while index < n:
slp = yield index
print(f'传入 {slp} ,类型{type(slp)} :')
index += 1
test2 = test2_yield(10)
print(test2.send(None))
print(test2.send(2.9))
print(test2.send(33))
print(test2.send('hello'))
# ----- 输出-----
0
传入 2.9 ,类型<class 'float'> :
1
传入 33 ,类型<class 'int'> :
2
传入 hello ,类型<class 'str'> :
3
Process finished with exit code 0
- 不使用 next() 方法时, 必须使用 send(None) , 不激活协程会导致报错
当不激活协程时报错:
#屏蔽上面代码片段中的
print(test2.send(None))
#--输出----
Traceback (most recent call last): File
"tests.py", line 16, in <module>
print(test2.send(2)) TypeError: can't send non-None value to a just-started generator
- 传值,将 send() 方法传入的值给到生成器,
slp
的值是 send() 传入的值。