datum = yield
。这一下就让初学者瞬间觉得yield关键字不香了,本来以为yield就是简简单单的暂停执行顺手返回个值,结果还能放右边?>>> def simple_coroutine():
... print("-> coroutine started")
... x = yield
... print("-> coroutine received:", x)
...
>>> my_coro = simple_coroutine()
>>> my_coro
<generator object simple_coroutine at 0x0000019A681F27B0>
>>> next(my_coro)
-> coroutine started
>>> my_coro.send(42)
-> coroutine received: 42
Traceback (most recent call last):
File "<input>", line 1, in <module>
StopIteration
.send()
推送的值。def simple_coro2(a):
b = yield a
c = yield a + b
my_coro2 = simple_coro2(14)
next(my_coro2)
my_coro2.send(28)
my_coro2.send(99)
调用next(my_coro2),执行yield a,产出14。
调用my_coro2.send(28),把28赋值给b,然后执行yield a + b,产出42。
调用my_coro2.send(99),把99赋值给c,协程终止。
next(my_coro)
启动生成器,让程序在yield语句处暂停,然后才可以发送数据。这是因为协程有四种状态:'GEN_CREATED' 等待开始执行
'GEN_RUNNING' 解释器正在执行
'GEN_SUSPENDED' 在yield表达式处暂停
'GEN_CLOSED' 执行结束
next(my_coro)
预激,也可以调用my_coro.send(None)
预激,效果一样。from functools import wraps
def coroutine(func):
@wraps(func)
def primer(*args, **kwargs):
gen = func(*args, **kwargs)
next(gen)
return gen
return primer
自定义预激装饰器和yield from是不兼容的。
for c in "AB":
yield c
yield from "AB"
调用方
说白了就是main函数,也就是众所周知的程序入口main函数。
# the client code, a.k.a. the caller
def main(data): # <8>
results = {}
for key, values in data.items():
group = grouper(results, key) # <9>
next(group) # <10>
for value in values:
group.send(value) # <11>
group.send(None) # important! <12>
# print(results) # uncomment to debug
report(results)
委派生成器
就是包含了yield from语句的函数,也就是协程。
# the delegating generator
def grouper(results, key): # <5>
while True: # <6>
results[key] = yield from averager() # <7>
子生成器
就是yield from语句右边跟着的子协程。
# the subgenerator
def averager(): # <1>
total = 0.0
count = 0
average = None
while True:
term = yield # <2>
if term is None: # <3>
break
total += term
count += 1
average = total/count
return Result(count, average) # <4>
send
协程在yield from表达式处暂停时,main函数可以通过yield from表达式把数据发给yield from语句右边跟着的子协程。
yield
yield from语句右边跟着的子协程再把产出的值通过yield from表达式发给main函数。
throw
main函数通过group.send(None)
,传入一个None值,让yield from语句右边跟着的子协程的while循环终止,这样控制权才会交回协程,才能继续执行,否则会一直暂在yield from语句暂停。
StopIteration
yield from语句右边跟着的生成器函数返回之后,解释器会抛出StopIteration异常。并把返回值附加到异常对象上,此时协程会恢复。
close
main函数执行完以后,会调用close()方法退出协程。
@asyncio.coroutine
装饰器结合使用。def averager():
total = 0.0
count = 0
average = None
while True: # <1>
term = yield average # <2>
total += term
count += 1
average = total/count
# BEGIN TAXI_PROCESS
def taxi_process(ident, trips, start_time=0): # <1>
"""Yield to simulator issuing event at each state change"""
time = yield Event(start_time, ident, 'leave garage') # <2>
for i in range(trips): # <3>
time = yield Event(time, ident, 'pick up passenger') # <4>
time = yield Event(time, ident, 'drop off passenger') # <5>
yield Event(time, ident, 'going home') # <6>
# end of taxi process # <7>
# END TAXI_PROCESS
def main(end_time=DEFAULT_END_TIME, num_taxis=DEFAULT_NUMBER_OF_TAXIS,
seed=None):
"""Initialize random generator, build procs and run simulation"""
if seed is not None:
random.seed(seed) # get reproducible results
taxis = {i: taxi_process(i, (i+1)*2, i*DEPARTURE_INTERVAL)
for i in range(num_taxis)}
sim = Simulator(taxis)
sim.run(end_time)
参考资料: 《流畅的Python》第16章 协程 https://zhuanlan.zhihu.com/p/104918655
联系客服