国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Python中的協(xié)程

shinezejian / 2078人閱讀

摘要:協(xié)程的基本行為協(xié)程包含四種狀態(tài)等待開始執(zhí)行。協(xié)程中重要的兩個(gè)方法調(diào)用方把數(shù)據(jù)提供給協(xié)程。注意使用調(diào)用協(xié)程時(shí)會(huì)自動(dòng)預(yù)激,因此與裝飾器不兼容標(biāo)準(zhǔn)庫中的裝飾器不會(huì)預(yù)激協(xié)程,因此能兼容句法。因此,終止協(xié)程的本質(zhì)在于向協(xié)程發(fā)送其無法處理的異常。

導(dǎo)語:本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之控制流程篇的重點(diǎn)知識(shí)及個(gè)人心得,打算入門Python的朋友們可以來一起學(xué)習(xí)并交流。

本文重點(diǎn):

1、掌握協(xié)程的概念與行為;
2、掌握協(xié)程中的預(yù)激,終止和異常處理;
3、深入理解yield from的本質(zhì)作用。
一、協(xié)程介紹 1、協(xié)程概述

協(xié)程:指的是與調(diào)用方協(xié)作,產(chǎn)出由調(diào)用方提供的值。
語法結(jié)構(gòu):協(xié)程是定義體中包含yield關(guān)鍵字的函數(shù),一般使用生成器函數(shù)定義。
意義:協(xié)程中的yield關(guān)鍵字是一種控制流程工具。即不管數(shù)據(jù)如何流動(dòng),協(xié)程都會(huì)把控制權(quán)讓步給中心調(diào)度程序,從而激活其他的協(xié)程實(shí)現(xiàn)協(xié)作式多任務(wù)。

2、協(xié)程的基本行為

協(xié)程包含四種狀態(tài):

GEN_CREATED:等待開始執(zhí)行。

GEN_RUNNING:解釋器正在執(zhí)行。

GEN_SUSPENDED:在yield表達(dá)式處暫停。

GEN_CLOSED:執(zhí)行結(jié)束。

可使用inspect.getgeneratorstate(...)查詢協(xié)程所處的狀態(tài)。

協(xié)程中重要的兩個(gè)方法:

.send(datum):調(diào)用方把數(shù)據(jù)提供給協(xié)程。

next(coroutine):預(yù)激協(xié)程。

協(xié)程返回值:自Python3.3實(shí)現(xiàn)PEP 380以來對(duì)生成器函數(shù)做了兩處改動(dòng),一處是生成器可以返回值。

3、實(shí)例1:協(xié)程初級(jí)使用——計(jì)算平均值

下面將利用協(xié)程計(jì)算用戶傳入若干數(shù)值的平均值。

def average():
    total=0.0
    number=0
    average=None
    while True:
        term=yield average
        total+=term
        number+=1
        average=total/number
        print(average)

process=average()
next(process)#預(yù)激協(xié)程
process.send(5)#輸出5
process.send(10)#輸出7.5
process.send(15) #輸出10.0

小結(jié):協(xié)程執(zhí)行首先需要預(yù)激,使之準(zhǔn)備好然后讓步控制權(quán)。具體地說,協(xié)程在yield關(guān)鍵字所在的位置暫停執(zhí)行。在term=yield average這個(gè) 賦值語句中,右邊的代碼會(huì)在賦值之前執(zhí)行。 在暫停結(jié)束后,從先前阻塞的那行代碼開始,將yield 表達(dá)式的值賦給左邊的變量。

實(shí)例2:令協(xié)程返回值

from collections import namedtuple

Result = namedtuple("result","average count")

def average():
    total = 0.0
    number = 0
    average = None
    while True:
        term = yield
        if term is None:
            break
        total += term
        number += 1
        average=total/number
    return Result(average,number) 

分析:當(dāng)協(xié)程終止時(shí),可以在return表達(dá)式中返回值。并且return表達(dá)式通過把值綁定到StopIteration的value屬性上傳給調(diào)用方返回值。事實(shí)上這也符合生成器的常規(guī)行為——耗盡時(shí)拋出StopIteration異常。

二、協(xié)程的預(yù)激、終止與異常處理 1、預(yù)激協(xié)程

協(xié)程在使用前須預(yù)激,讓協(xié)程向前執(zhí)行到第一個(gè)yield表達(dá)式,準(zhǔn)備好作為活躍的協(xié)程使用。
預(yù)激的本質(zhì)方法:

next(coroutine):常見的標(biāo)準(zhǔn)方法。

同時(shí)首次發(fā)送coroutine.send(None)也可以調(diào)用next(coroutine),實(shí)現(xiàn)相同功能,但缺乏可讀性。

基于本質(zhì)方法,我們衍生出自定義預(yù)激協(xié)程的裝飾器的方法,避免忘記預(yù)激協(xié)程。
coroutine:預(yù)激協(xié)程的裝飾器

from functools import wraps
def coroutine(func):
    @wraps(func)#把func相關(guān)屬性復(fù)制過來
    def manage(*args,**kwargs):
        gen=func(*args,**kwargs)#獲取生成器對(duì)象
        next(gen)#預(yù)激協(xié)程
        return gen#返回協(xié)程
    return manage

只需將@coroutine語法糖加在生成器函數(shù)上,就可以通過構(gòu)造生成器對(duì)象獲取活躍的協(xié)程。
注意:

使用yield from調(diào)用協(xié)程時(shí)會(huì)自動(dòng)預(yù)激,因此與@coroutine裝飾器不兼容;

Python3.4標(biāo)準(zhǔn)庫中的asyncio.coroutine裝飾器不會(huì)預(yù)激協(xié)程,因此能兼容yield from句法。

2、終止協(xié)程

協(xié)程中未處理的異常會(huì)向上冒泡,傳給next函數(shù)或send方法的調(diào)用方。
因此,終止協(xié)程的本質(zhì)在于向協(xié)程發(fā)送其無法處理的異常。下面介紹三種方法終止協(xié)程:

發(fā)送哨符值。常用None和Ellipsis,甚至StopIteration類也可以發(fā)送。

generator.throw(exc_type[,exc_value[,traceback]])
令生成器在暫停的yield表達(dá)式處拋出指定的異常。若生成器處理了此異常,則生成器向前執(zhí)行到下一個(gè)yield表達(dá)式,而產(chǎn)出的值會(huì)成為調(diào)用generator.throw得到的返回值。否則,異常會(huì)向上冒泡,傳到調(diào)用方的上下文中。

generator.close()
令生成器在暫停的yield表達(dá)式處拋出GeneratorExit異常。如果生成器不處理此異常,或者跑出來StopIteration,調(diào)用方不會(huì)報(bào)錯(cuò)。如果收到GeneratorExit異常,生成器一定不能產(chǎn)出值,否則解釋器會(huì)拋出RuntimeError異常。

后兩種方法是自Python2.5開始顯式發(fā)送異常的兩個(gè)方法,建議使用后兩種方法來終止協(xié)程。

3、處理異常

在使用協(xié)程的過程中會(huì)產(chǎn)生一些需要處理的異常,此時(shí)可利用try/except處理。如果不管協(xié)程如何結(jié)束都要做一些清理工作,請(qǐng)使用try/finally處理。

實(shí)例1:使用try/finally在協(xié)程終止時(shí)執(zhí)行操作

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: {!r}".format(x))
        finally:
            print("-> coroutine ending")
三、yield from結(jié)構(gòu) 1、yield from結(jié)構(gòu)介紹

作用介紹:
本質(zhì)作用是打開雙向通道,把最外層的調(diào)用方與最內(nèi)層的子生成器連接起來,這樣兩者可以直接發(fā)送和產(chǎn)出值,還可以直接傳入異常。
替代產(chǎn)出值的嵌套for循環(huán)。

執(zhí)行機(jī)制:
(1)在生成器gen中使用yield from subgen()時(shí),subgen會(huì)獲得控制權(quán),把產(chǎn)出的值傳給gen的調(diào)用方,即調(diào)用方可以直接控制subgen。與此同時(shí),gen會(huì)阻塞,等待subgen終止。
(2)yield from結(jié)構(gòu)會(huì)在內(nèi)部自動(dòng)捕獲StopIteration異常,還會(huì)把對(duì)應(yīng)的value屬性值變成yield from表達(dá)式的值。

2、yield from的應(yīng)用

實(shí)例1:對(duì)yield from架構(gòu)雙向通道本質(zhì)的深入理解
下面我們結(jié)合實(shí)例深入理解yield from結(jié)構(gòu)。假設(shè)我們需要利用yield from分別計(jì)算一個(gè)班級(jí)男女生身高和體重的平均值,并予以輸出。采用“外部調(diào)用方+委派生成器+子生成器”的結(jié)構(gòu)進(jìn)行設(shè)計(jì),結(jié)構(gòu)示意圖如下:

實(shí)例代碼:

from collections import namedtuple
Result=namedtuple("Result","average number")

def subaverager():#子生成器經(jīng)委派生成器處理外部數(shù)據(jù),并將值返回給委派生成器。
    total = 0.0
    number = 0
    average = None
    while True:
        term = yield
        if term is None:#外部調(diào)用方控制子生成器終止的關(guān)鍵語句。
            break
        total += term
        number += 1
        average=total/number
    return Result(average,number)

def averager(results,key):#委托生成器架構(gòu)雙向通道。
    while True:#避免StopIteration。當(dāng)?shù)玫阶由善鞯姆祷刂禃r(shí),程序會(huì)執(zhí)行到下一個(gè)yield。
        results[key]=yield from subaverager()

def main(grouper):
    results={}
    for key,group in grouper.items():
        term = averager(results,key)#構(gòu)建生成器對(duì)象。
        next(term)
        for value in group:
            term.send(value)
        term.send(None)#外部調(diào)用方控制子生成器終止的語句。
        print(results)
    result(results)

def result(results):#格式化輸出協(xié)程返回的處理數(shù)據(jù)。
    for key,value in results.items():
        gender,unit=key.split(";")
        print("{} {} averaging {:.2f} {}.".format(
            value.number,gender,value.average,unit))

data = {
"girls;kg":
[40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5],
"girls;m":
[1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43],
"boys;kg":
[39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],
"boys;m":
[1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46],
}

if __name__=="__main__":
    main(data)

思路擴(kuò)展:上例展示的結(jié)構(gòu)中僅有一個(gè)委派生成器和一個(gè)子生成器。事實(shí)上,這種調(diào)用關(guān)系可以擴(kuò)展到更多的委托生成器上。即把多個(gè)委派生成器連接到一起。一個(gè)委派生成器調(diào)用另一個(gè)子生成器,這個(gè)子生成器本身也是委派生成器。這種鏈?zhǔn)浇Y(jié)構(gòu)最終以一個(gè)只使用yield的簡(jiǎn)單生成器結(jié)束,或者任何的可迭代對(duì)象結(jié)束。

實(shí)例2:替代產(chǎn)出值的嵌套for循環(huán)

def gen():
for c in "AB":
 yield c
 for i in range(1, 3):
 yield i
print(list(gen()))#輸出["A", "B", 1, 2]

可以簡(jiǎn)化成:

def gen():
yield from "AB"
yield from range(1, 3)
print(list(gen()))#輸出["A", "B", 1, 2]
3、PEP380中總結(jié)的yield from的六點(diǎn)行為

子生成器產(chǎn)出的值都直接傳給委派生成器的調(diào)用方。

使用send()方法發(fā)給委派生成器的值都直接傳給子生成器。如果發(fā)送None會(huì)調(diào)用生成器的__next__()方法。如果發(fā)送的不是None,那么委派生成器恢復(fù)運(yùn)行。任何其他異常都會(huì)向上冒泡,傳給委派生成器。

生成器退出時(shí),生成器中的return表達(dá)式會(huì)觸發(fā)StopIteration(expr)異常拋出。

yield from表達(dá)式的值是子生成器終止時(shí)傳給StopIteration異常的第一個(gè)參數(shù)。

傳入委派生成器的異常,除了GeneratorExit之外都傳給子生成器的throw()方法。如果調(diào)用throw()方法時(shí)拋出StopIteration異常,委派生成器恢復(fù)運(yùn)行。StopIteration之外的異常會(huì)向上冒泡,傳給委派生成器。

如果把 GeneratorExit 異常傳入委派生成器, 或者在委派生成器上調(diào)用 close() 方法, 那么在子生成器上調(diào)用 close() 方法, 如果它有的話。 如果調(diào)用 close() 方法導(dǎo)致異常拋出, 那么異常會(huì)向上冒泡, 傳給委派生成器; 否則, 委派生成器拋出GeneratorExit 異常。

四、協(xié)程與生成器異同

生成器用于生成供迭代的數(shù)據(jù)。

協(xié)程是數(shù)據(jù)的消費(fèi)者,能完成協(xié)作式多任務(wù)活動(dòng)。

協(xié)程與迭代無關(guān)。盡管在協(xié)程中會(huì)使用 yield 產(chǎn)出值, 但這與迭代無關(guān)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/44636.html

相關(guān)文章

  • Python中的并發(fā)處理之使用asyncio包

    摘要:并發(fā)用于制定方案,用來解決可能但未必并行的問題。在協(xié)程中使用需要注意兩點(diǎn)使用鏈接的多個(gè)協(xié)程最終必須由不是協(xié)程的調(diào)用方驅(qū)動(dòng),調(diào)用方顯式或隱式在最外層委派生成器上調(diào)用函數(shù)或方法。對(duì)象可以取消取消后會(huì)在協(xié)程當(dāng)前暫停的處拋出異常。 導(dǎo)語:本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之控制流程篇的重點(diǎn)知識(shí)及個(gè)人心得,打算入門Python的朋友們可以來一起學(xué)習(xí)并交流。 本文重點(diǎn): 1、了解asyncio...

    tuniutech 評(píng)論0 收藏0
  • Tornado 4.3文檔翻譯: 用戶指南-協(xié)程

    摘要:譯者說于年月日發(fā)布,該版本正式支持的關(guān)鍵字,并且用舊版本編譯同樣可以使用這兩個(gè)關(guān)鍵字,這無疑是一種進(jìn)步。其次,這是最后一個(gè)支持和的版本了,在后續(xù)的版本了會(huì)移除對(duì)它們的兼容。 譯者說 Tornado 4.3于2015年11月6日發(fā)布,該版本正式支持Python3.5的async/await關(guān)鍵字,并且用舊版本CPython編譯Tornado同樣可以使用這兩個(gè)關(guān)鍵字,這無疑是一種進(jìn)步。其次...

    SimonMa 評(píng)論0 收藏0
  • 協(xié)程原理】 - 為什么greenlet的狀態(tài)無法被保存

    摘要:特別是最火的協(xié)程框架也無法保存狀態(tài),讓人非常惋惜。但是因?yàn)闂5谋旧頍o法持久化,所以也就無法持久化。其難度在于,假設(shè)整個(gè)要持久化的調(diào)用棧全部都是內(nèi)的,比如純的。采取的是暴力地把整個(gè)棧區(qū)域拷貝到上的方式來保存其狀態(tài)。 python主流的協(xié)程實(shí)現(xiàn)有五種: cPython的generator cPython的greenlet cPython的fibers stackless python ...

    verano 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<