Python控制流程协程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python控制流程协程相关的知识,希望对你有一定的参考价值。
"""
# 16.2 用过协程的生成器的基本行为
#例子16-1 可能是协程最简单的使用演示
def simple_coroutine():
print(‘-> coroiutine started‘)
x = yield
print(‘-> coroutine recived:‘,x)
my_coro = simple_coroutine()
print(my_coro) #<generator object simple_coroutine at 0x10900f9e8>
#print(next(my_coro))
‘‘‘
-> coroiutine started
None
‘‘‘
#my_coro.send(42)
‘‘‘
-> coroutine recived: 42
StopIteration
‘‘‘
#【备注】协程可以身处四个状态中的一个。当前状态可以使用inspect.getgeneratorstate()函数确定,该函数会返回下述字符串中的一个。
#... ‘GEN_CREATED‘等待开始执行。 ‘GEN_RUNNING‘ 解释器正在执行 ‘GEN_SUSPENDED‘在yield表达式处暂停 ‘GEN_CLOSED‘执行结束。
#...因为send方法的参数会称为暂停的yield表达式的值,所以,仅当协程处于暂停状态时才能调用send方法。不过,如果协程还没激活(即,状态是‘GEN_CREATED‘),情况就不同了。因此,始终要调用next()激活协程-也可以调用my_coro.sen(None),效果一样
#...如果创建协程对象后立即把None之外的值发给他,会出现下述错误:
my_coro = simple_coroutine()
my_coro.send(1729) #TypeError: can‘t send non-None value to a just-started generator
# 例子16-2 产出两个值的协程
def simple_coro2(a):
print(‘-> Started:a = ‘,a)
b = yield a
print(‘-> Received:b = ‘,b)
c = yield (a+b)
print(‘-> Received:c = ‘,c)
my_coro2 = simple_coro2(14)
from inspect import getgeneratorstate
print(getgeneratorstate(my_coro2)) #GEN_CREATED
print(next(my_coro2))
‘‘‘
-> Started:a = 14
14
‘‘‘
print(getgeneratorstate(my_coro2)) #GEN_SUSPENDED
print(my_coro2.send(28))
‘‘‘
-> Started:b = 28
42
‘‘‘
print(my_coro2.send(99))
‘‘‘
-> Received:c = 99
Traceback (most recent call last):
File "/Users/suren/PycharmProjects/fluentPython/kongzhiliucheng/xiecheng.py", line 47, in <module>
my_coro2.send(99)
StopIteration
‘‘‘
print(getgeneratorstate(my_coro2)) #‘GEN_CLOSED‘
#例子16-3 一个计算移动平均值的协程
def averager():
total = 0.0
count = 0
average = None
while True:#这个无限循环表明,只要调用方不断把值发给这个协程,它就会一直接收值,然后生成结果。仅当调用方在协程上调用.close()方法,或者没有对协程引用而被垃圾回收程序回收时,这个协程才终止
term = yield average
total += term
count += 1
average = total/count
coro_avg = averager()
print(next(coro_avg)) #None
print(coro_avg.send(10)) #10.0
print(coro_avg.send(30)) #20.0
print(coro_avg.send(5)) #15.0
#16.4 预激程序的装饰器
from functools import wraps
def coroutine(func):
@wraps(func)
def primer(*args,**kwargs):
gen = func(*args,**kwargs)
next(gen)
return gen
return primer
@coroutine
def averager():
total = 0.0
count = 0
average = None
while True:
term = yield average
total += term
count += 1
average = total/count
coro_avg = averager()
from inspect import getgeneratorstate
print(getgeneratorstate(coro_avg)) #GEN_SUSPENDED
print(coro_avg.send(10)) #10.0
print(coro_avg.send(30)) #20.0
print(coro_avg.send(5)) #15.0
#16.5 终止协程和异常处理
#例子 16-7 未处理的异常会导致协程终止
from functools import wraps
def coroutine(func):
@wraps(func)
def primer(*args,**kwargs):
gen = func(*args,**kwargs)
next(gen)
return gen
return primer
@coroutine
def averager():
total = 0.0
count = 0
average = None
while True:
term = yield average
total += term
count += 1
average = total/count
coro_avg = averager()
print(coro_avg.send(40)) #40.0
print(coro_avg.send(50)) #45.0
print(coro_avg.send(‘spam‘)) #TypeError: unsupported operand type(s) for +=: ‘float‘ and ‘str‘。此时,由于在协程里没有处理异常,协程会终止。如果试图重新激活协程,会抛出
print(coro_avg.send(60)) #不会处理
# 例子16-8 在协程中处理异常代码
class DemoException(Exception):
‘‘‘为这次演示定义的异常类型‘‘‘
def demo_exc_handling():
print(‘-> coroutine started‘)
while True:
try:
x = yield
except DemoException:
print(‘*** DemoException handled.Continuing...‘)
else: #如果没有异常,则显示接收到的值
print(‘->coroutine received:{!s}‘.format(x))
raise RuntimeError(‘This line should never run.‘) #这一行永远不会执行,因为只有未处理的异常才会终止那个无限循环
#激活和关闭demo_exc_handling,没有异常
exc_coro = demo_exc_handling()
print(next(exc_coro)) #coroutine started
print(exc_coro.send(11)) #->coroutine received:11
print(exc_coro.send(22)) #->coroutine received:22
exc_coro.close()
from inspect import getgeneratorstate
print(getgeneratorstate(exc_coro)) #GEN_CLOSED
#把DemoException异常传入demo_exc_handling不会导致协程中止
exc_coro = demo_exc_handling()
print(next(exc_coro)) #-> coroutine started
print(exc_coro.send(11)) #->coroutine received:11
print(exc_coro.throw(DemoException)) #*** DemoException handled.Continuing...
print(getgeneratorstate(exc_coro)) #GEN_SUSPENDED
#如果无法处理传入的异常,协程会终止
exc_coro = demo_exc_handling()
print(next(exc_coro)) #-> coroutine started
print(exc_coro.send(11))
print(exc_coro.throw(ZeroDivisionError))
‘‘‘
Traceback (most recent call last):
File "/Users/suren/PycharmProjects/fluentPython/kongzhiliucheng/xiecheng.py", line 172, in <module>
print(exc_coro.throw(ZeroDivisionError))
File "/Users/suren/PycharmProjects/fluentPython/kongzhiliucheng/xiecheng.py", line 145, in demo_exc_handling
x = yield
ZeroDivisionError
‘‘‘
print(getgeneratorstate(exc_coro)) #GEN_CLOSED
#例子16-12 使用try/finally 块在协程终止时执行操作
class DemoException(Exception):
‘‘‘为这次演示定义的异常类型‘‘‘
def demo_finally():
print(‘-> coroutine started‘)
try:
while True:
try:
x = yield
except DemoException:
print(‘*** DemoException handled.Continuing.....‘)
else:
print(‘-> coroutine received:{!s}‘.format(x))
finally:
print(‘->coroutine ending‘)
# 激活和关闭demo_exc_handling,没有异常
exc_coro = demo_finally()
print(next(exc_coro)) #coroutine started 换行后打印 ->coroutine ending
print(exc_coro.send(11)) #->coroutine received:11 换行后打印 ->coroutine ending
print(exc_coro.send(22)) #->coroutine received:22 换行后打印 ->coroutine ending
exc_coro.close()
from inspect import getgeneratorstate
print(getgeneratorstate(exc_coro)) #GEN_CLOSED 换行后打印 ->coroutine ending
# 把DemoException异常传入demo_exc_handling不会导致协程中止
exc_coro = demo_finally()
print(next(exc_coro)) #-> coroutine started 换行后打印 ->coroutine ending
print(exc_coro.send(11)) #->coroutine received:11 换行后打印 ->coroutine ending
print(exc_coro.throw(DemoException)) #*** DemoException handled.Continuing... 换行后打印 ->coroutine ending
print(getgeneratorstate(exc_coro)) #GEN_SUSPENDED 换行后打印 ->coroutine ending
#如果无法处理传入的异常,协程会终止
exc_coro = demo_finally()
print(next(exc_coro)) #-> coroutine started 换行后打印 ->coroutine ending
print(exc_coro.send(11))
#print(exc_coro.throw(ZeroDivisionError))
‘‘‘
Traceback (most recent call last):
File "/Users/suren/PycharmProjects/fluentPython/kongzhiliucheng/xiecheng.py", line 220, in <module>
print(exc_coro.throw(ZeroDivisionError))
->coroutine ending
File "/Users/suren/PycharmProjects/fluentPython/kongzhiliucheng/xiecheng.py", line 192, in demo_finally
x = yield
ZeroDivisionError
->coroutine ending
‘‘‘
from inspect import getgeneratorstate
#print(getgeneratorstate(exc_coro)) #GEN_CLOSED 换行后打印 ->coroutine ending
#让协程返回值
#例子16-14
from collections import namedtuple
Result = namedtuple(‘Result‘,‘count average‘)
def averager():
total = 0.0
count = 0
average = None
while True:
term = yield
if term is None:
break
total += term
count += 1
average = total/count
return Result(count,average)
coro_avg = averager()
print(next(coro_avg)) #无产出
print(coro_avg.send(10)) #无产出
print(coro_avg.send(30)) #无产出
print(coro_avg.send(6.5)) #无产出
#print(coro_avg.send(None)) #StopIteration: Result(count=3, average=15.5)
#例子16-15
from collections import namedtuple
Result = namedtuple(‘Result‘,‘count average‘)
def averager():
total = 0.0
count = 0
average = None
while True:
term = yield
if term is None:
break
total += term
count += 1
average = total/count
return Result(count,average)
coro_avg = averager()
print(next(coro_avg)) #无产出
print(coro_avg.send(10)) #无产出
print(coro_avg.send(30)) #无产出
print(coro_avg.send(6.5)) #无产出
try:
coro_avg.send(None)
except StopIteration as exc:
result = exc.value
print(result) #Result(count=3, average=15.5)
"""
以上是关于Python控制流程协程的主要内容,如果未能解决你的问题,请参考以下文章