yield 生成器, 当函数中有yield, 那么这个函数编程生成器, 对其进行函数调用, 不会执行, 会返回一个生成器对象
In [1]: def createNum():
...: print("__start__")
...: a, b = 0, 1
...: for i in range(5):
...: print("__1__")
...: yield b
...: print("__2__")
...: a, b = b, a+b
...: print("__3__")
...: print("__stop__")
...:
In [3]: a
Out[3]: <generator object createNum at 0x000001FEF6C8AB48>
In [5]: type(a)
Out[5]: generator
生成器对象使用next()开始执行
In [4]: next(a)
__start__
__1__
Out[4]: 1
可见, 一次next()调用, 程序从上往下执行, 恰好到yield b处停止, 并返回yield后面变量的值1
进行下一次next()调用
In [6]: next(a)
__2__
__3__
__1__
Out[6]: 1
程序从上一次next()执行的位置继续向下执行, 直到下一次遇到yield b
通过for执行, 不会出现StopIteration错误
In [7]: for each in a:
...: print(each)
...:
__2__
__3__
__1__
2
__2__
__3__
__1__
3
__2__
__3__
__1__
5
__2__
__3__
__stop__
In [1]: def test():
...: i = 0
...: while i < 5:
...: temp = yield i
...: print(temp)
...: i += 1
...:
试想, temp的值是否是yield后面i的值
In [4]: t.__next__()
Out[4]: 0
第一次执行, 到yield停止, 返回i的值
In [5]: t.__next__()
None
Out[5]: 1
第二次执行, 到yield停止, 期间打印None, 最后返回i的值, 可见, 其并未如我们预期所想, yield i整体没有任何值, 那么如何才能实现给temp赋值的效果呢?
In [6]: t.send('send')
send
Out[6]: 2
发现, send()和next()都可以让生成器向下执行, 不同的是, send(arg)通过一个参数, 给yield i整体赋值
需要注意的是, 在生成器的第一次使用时, 由于程序并未执行到
yield, 所以此时通过send()函数传参调用生成器会报错TypeError: can't send non-None value to a just-started generator, 但是可以传入参数None来使生成器走到yield处
协程简单实现
In [25]: def test1():
...: while True:
...: print('__1__')
...: yield None
...:
In [26]: def test2():
...: while True:
...: print('__2__')
...: yield None
...:
In [27]: t1 = test1()
In [28]: t2 = test2()
In [29]: import time
In [30]: while True:
...: t1.__next__()
...: t2.__next__()
...: time.sleep(1)
...:
__1__
__2__
__1__
__2__
__1__
__2__
__1__
__2__
__1__
__2__
__1__
__2__
__1__
__2__
通过生成器的中断特性以及next()的执行, 实现程序间的跳转, 完成简单协程











网友评论