1. 程式人生 > >【Python】【控制流程】【三】【協程】

【Python】【控制流程】【三】【協程】

trace 執行 this tool 引用 給他 異常 rmp 解釋

"""
# 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】【控制流程】【三】【協程】