理解协程,先要对生成器有概念;
生成器: 函数中有yield , 或者生成器表达式(x for x in range(5)) 都会被编译成生成器.
生成器内部实现了迭代协议,即__iter__ , __next__ / next() . 所以可以用于迭代.
生成器不会像列表一样一次在内存中展开所有的值, 而是拿一次计算一次.
协程可以使用 send 来交互.
比如
1.x = yield 这个表达式不产生值. 即在yield 后没有需要产出的值
2.x = yield 1 这个表达式会产出一个值
这里用产出/产生 而不使用返回值, 是为了和return 区别.
而send(y) 的作用是 把 y 赋予 x .
下面具体说明
"""
协程 与 生成器函数类似, 内部都有yield关键字,
额外的函数调用 (send , close , throw)
执行到yield 时, 函数暂停.
注意 , yield 是产生一个值 , 不是返回一个值.
协程 需要激活一下, 使用next, 或send(None)
"""
def func(a):
print('args , a:',a)
b = yield a #yield产生了a, 同时暂停了执行.此时, b 还未赋值
print('recv b :' , b)
c = yield a*b
print('recv c:' , c)
m = func(1)
print(inspect.getgeneratorstate(m))
print(next(m)) #激活
print(m.send(2))
print(m.send(0))
#GEN_CREATED
#args , a: 1
#1
#recv b : 2
#2
#recv c: 0
#停止: close , throw
def demo_func():
while 1:
try:
x = yield
except Exception:
print('处理异常')
else:
print('接受到的值:',x)
m = demo_func()
next(m) #激活
m.send(1)
m.send(2)
m.send(3)
m.close()
#yield from
#yield from 可以替代for
#yield from 'abc' -> 首先做的是 iter('abc') ,即 yield from 后面只要是一个可迭代对象
def g():
for i in range(5):
yield i
#把上面的例子 替换
def gen():
yield from range(5)
d = gen()
print(list(d))
#[0, 1, 2, 3, 4]
#yield from 作为委派生成器
def get_total():
totoal = 0
while 1:
print('子生成器进入循环')
num = yield
print('子生成器获取值:',num)
if num is None:
return totoal
totoal += num
def gen(res_arr):
print('委派生成器启动')
while 1:
print('委派生成器开始委托任务')
res = yield from get_total()
print('委派生成器获取值:',res)
res_arr.append(res)
res_arr = []
g = gen(res_arr)
next(g)
g.send(1)
g.send(2)
g.send(None)
print('total:',res_arr)