成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

流暢的python讀書筆記-第十六章-攜(協(xié))程

wanglu1209 / 3357人閱讀

摘要:當前狀態(tài)可以使用函數(shù)確定,該函數(shù)會返回下述字符串中的一個。解釋器正在執(zhí)行。打印消息,然后協(xié)程終止,導致生成器對象拋出異常。實例運行完畢后,返回的值綁定到上。

協(xié)程

協(xié)程可以身處四個狀態(tài)中的一個。

當前狀態(tài)可以使用inspect.getgeneratorstate(...) 函數(shù)確定,該函數(shù)會返回下述字符串中的一個。

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

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

"GEN_SUSPENDED"
  在 yield 表達式處暫停。

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

def simple_coro2(a):
    print("-> Started: a =", a)


    b = yield a  #等著賦值b 把a甩出去
    print("-> Received: b =", b)
    c = yield a + b
    print("-> Received: c =", c)


my_coro_2 = simple_coro2(14)

from inspect import getgeneratorstate

print(getgeneratorstate(my_coro_2))

print(next(my_coro_2))
getgeneratorstate(my_coro_2)


print(my_coro_2.send(28))

# 沒有yield 出來 所以沒有返回值
print(my_coro_2.send(99))

getgeneratorstate(my_coro_2)

getgeneratorstate 函數(shù)指明,處于 GEN_SUSPENDED 狀態(tài)(即協(xié)程在 yield 表達式處暫停)。

? 把數(shù)字 99 發(fā)給暫停的協(xié)程;計算 yield 表達式,得到 99,然后把那個數(shù)綁定給 c。
打印 -> Received: c = 99 消息,然后協(xié)程終止,導致生成器對象拋出
StopIteration 異常。

另一個案例
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(next(coro_avg))

print(coro_avg.send(10))

print(coro_avg.send(15))

print(coro_avg.send(20))

調(diào)用 next 函數(shù),預激協(xié)程。
? 這個無限循環(huán)表明,只要調(diào)用方不斷把值發(fā)給這個協(xié)程,它就會一直接收值,然后生
成結(jié)果。僅當調(diào)用方在協(xié)程上調(diào)用 .close() 方法,或者沒有對協(xié)程的引用而被垃圾回收
程序回收時,這個協(xié)程才會終止。
? 這里的 yield 表達式用于暫停執(zhí)行協(xié)程,把結(jié)果發(fā)給調(diào)用方;還用于接收調(diào)用方后面
發(fā)給協(xié)程的值,恢復無限循環(huán)。

終止協(xié)程和異常處理

發(fā)送某個哨符值,讓協(xié)程退出。
內(nèi)置的 None 和Ellipsis 等常量經(jīng)常用作哨符值。

Ellipsis 的優(yōu)點是,數(shù)據(jù)流中不太常有這個值。

throw

generator.throw(exc_type[, exc_value[, traceback]])

致使生成器在暫停的 yield 表達式處拋出指定的異常。

如果生成器處理了拋出的異常,代碼會向前執(zhí)行到下一個 yield 表達式,而產(chǎn)出的值會成為調(diào)用 generator.throw方法得到的返回值。

generator.close()

致使生成器在暫停的 yield 表達式處拋出 GeneratorExit 異常。

如果生成器沒有處理這個異常,或者拋出了 StopIteration 異常(通常是指運行到結(jié)尾),調(diào)用方不會報錯。

如果收到 GeneratorExit 異常,生成器一定不能產(chǎn)出值,否則解釋器會拋出
RuntimeError 異常。

兩種停止方式

exc_coro.throw(ZeroDivisionError)
exc_coro.close()

讓協(xié)程返回值
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()
next(coro_avg)

coro_avg.send(30)
coro_avg.send(6.5)

try:
    coro_avg.send(None)
except StopIteration as exc:
    result = exc.value
    print(result)

捕獲 StopIteration 異常,獲取 averager 返回的值

yield from 結(jié)構(gòu)會在內(nèi)部自動捕獲 StopIteration 異常。
這種處理方式與 for 循環(huán)處理 StopIteration 異常的方式一樣:循環(huán)機制使用用戶易于理解的方式處理異常。
對 yield from 結(jié)構(gòu)來說,解釋器不僅會捕獲 StopIteration 異常,還會把value 屬性的值變成 yield from 表達式的值。
使用yield from

yield from 結(jié)構(gòu)唯一的作用是替代產(chǎn)出值的嵌套 for 循環(huán), 這句話不對

yield from 的主要功能是打開雙向通道,把最外層的調(diào)用方與最內(nèi)層的子生成器連接起來,

這樣二者可以直接發(fā)送和產(chǎn)出值,還可以直接傳入異常,

而不用在位于中間的協(xié)程中添加大量處理異常的樣板代碼。

有了這個結(jié)構(gòu),協(xié)程可以通過以前不可能的方式委托職責。

案例

委派生成器
  包含 yield from 表達式的生成器函數(shù)。

子生成器
  從 yield from 表達式中 部分獲取的生成器。這就是 PEP 380 的標題
(“Syntax for Delegating to a Subgenerator”)中所說的“子生成器”(subgenerator)。

調(diào)用方
  PEP 380 使用“調(diào)用方”這個術(shù)語指代調(diào)用委派生成器的客戶端代碼。在不同的語境
中,我會使用“客戶端”代替“調(diào)用方”,以此與委派生成器(也是調(diào)用方,因為它調(diào)用了子
生成器)區(qū)分開。

不使用yield from

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)  # ?



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],
}




def main(data):
    result = {}

    for key, values in data.items():
        coro_avg = averager()
        next(coro_avg)
        for value in values:
            coro_avg.send(value)

        try:
            coro_avg.send(None)
        except StopIteration as exc:
            result[key] = exc.value

    print(result)



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

這里的try: catch stop異常要一直存在

用yiled from 及委派生成器作用

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)  # ?



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],
}


def grouper(results):
    while True:
        res_obj = yield from averager()
        results.append(res_obj)




def main(data):
    results = []
    for key, values in data.items():

        coro_avg = grouper(results)
        next(coro_avg)

        for value in values:
            coro_avg.send(value)

        # 這個None是停止返回 哨兵
        coro_avg.send(None)


    print(results)

    # report(result)


# 輸出報告
def report(results):
    for key, result in sorted(results.items()):
        group, unit = key.split(";")
        print("{:2} {:5} averaging {:.2f}{}".format(
            result.count, group, result.average, unit))


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

官方的案例

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)  # ?


# 委派生成器
def grouper(results, key):  # ?
    while True:  # ?
        results[key] = yield from averager()  # ?




# 客戶端代碼,即調(diào)用方
def main(data):  # ?
    results = {}
    for key, values in data.items():
        group = grouper(results, key)  # ?
        next(group)  # ?
        for value in values:
            group.send(value)  # ?
        group.send(None)  # 重要! #?

    print(results)  # 如果要調(diào)試,去掉注釋

    # report(results)


# 輸出報告
def report(results):
    for key, result in sorted(results.items()):
        group, unit = key.split(";")
        print("{:2} {:5} averaging {:.2f}{}".format(
            result.count, group, result.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)

? 至關(guān)重要的終止條件。如果不這么做,使用 yield from 調(diào)用這個協(xié)程的生成器會永
遠阻塞。
? 返回的 Result 會成為 grouper 函數(shù)中 yield from 表達式的值

? 這個循環(huán)每次迭代時會新建一個 averager 實例;每個實例都是作為協(xié)程使用的生成
器對象。
? grouper 發(fā)送的每個值都會經(jīng)由 yield from 處理,通過管道傳給 averager 實
例。grouper 會在 yield from 表達式處暫停,等待 averager 實例處理客戶端發(fā)來的
值。averager 實例運行完畢后,返回的值綁定到 results[key] 上。while 循環(huán)會不斷
創(chuàng)建 averager 實例,處理更多的值。

yield from 結(jié)構(gòu)會在內(nèi)部自動捕獲 StopIteration 異常。這種處理方
式與 for 循環(huán)處理 StopIteration 異常的方式一樣:循環(huán)機制使用用戶易于理解的方式
處理異常。對 yield from 結(jié)構(gòu)來說,解釋器不僅會捕獲 StopIteration 異常,還會把
value 屬性的值變成 yield from 表達式的值。
總結(jié)

這里先不總結(jié) 帶我把協(xié)程 程序加進去

如何使用協(xié)程在單個線程中管理并發(fā)活動。

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/42066.html

相關(guān)文章

  • 流暢python讀書筆記-第六章-使用一等函數(shù)實現(xiàn)設(shè)計模式

    摘要:在復雜的情況下,需要具體策略維護內(nèi)部狀態(tài)時,可能需要把策略和享元模式結(jié)合起來。函數(shù)比用戶定義的類的實例輕量,而且無需使用享元模式,因為各個策略函數(shù)在編譯模塊時只會創(chuàng)建一次。 一等函數(shù)實現(xiàn)設(shè)計模式 經(jīng)典的策略模式定義 定義一系列算法,把它們一一封裝起來,并且使它們可以相互替換。本模式使得算法可以獨立于使用它的客戶而變化。 案例 假如一個網(wǎng)店制定了下述折扣規(guī)則。 有 1000 或以上積分...

    cnsworder 評論0 收藏0
  • python協(xié)2:yield from 從入門到精通

    摘要:于此同時,會阻塞,等待終止。子生成器返回之后,解釋器會拋出異常,并把返回值附加到異常對象上,只是委派生成器恢復。實例運行完畢后,返回的值綁定到上。這一部分處理調(diào)用方通過方法傳入的異常。之外的異常會向上冒泡。 上一篇python協(xié)程1:yield的使用介紹了: 生成器作為協(xié)程使用時的行為和狀態(tài) 使用裝飾器預激協(xié)程 調(diào)用方如何使用生成器對象的 .throw(...) 和 .close()...

    vpants 評論0 收藏0
  • python協(xié)1:yield 10分鐘入門

    摘要:協(xié)程定義協(xié)程的底層架構(gòu)是在中定義,并在實現(xiàn)的。為了簡化,我們會使用裝飾器預激協(xié)程。執(zhí)行上述代碼結(jié)果如下出錯的原因是發(fā)送給協(xié)程的值不能加到變量上。示例使用和方法控制協(xié)程。 最近找到一本python好書《流暢的python》,是到現(xiàn)在為止看到的對python高級特性講述最詳細的一本??戳藚f(xié)程一章,做個讀書筆記,加深印象。 協(xié)程定義 協(xié)程的底層架構(gòu)是在pep342 中定義,并在python2...

    MartinDai 評論0 收藏0
  • 流暢python讀書筆記-第十四章-可迭代對象、迭代器和生成器

    摘要:可迭代的對象迭代器和生成器理念迭代是數(shù)據(jù)處理的基石??傻膶ο笈c迭代器的對比從可迭代的對象中獲取迭代器標準的迭代器接口有兩個方法。此外,也沒有辦法還原迭代器。最終,函數(shù)的定義體返回時,外層的生成器對象會拋出異常這一點與迭代器協(xié)議一致。 可迭代的對象、迭代器和生成器 理念 迭代是數(shù)據(jù)處理的基石。掃描內(nèi)存中放不下的數(shù)據(jù)集時,我們要找到一種惰性獲取數(shù)據(jù)項的方式,即按需一次獲取一個數(shù)據(jù)項。這...

    kohoh_ 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<