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

資訊專欄INFORMATION COLUMN

生成器進化到協程 Part 1

lemon / 491人閱讀

摘要:生成器用于定義生成器函數只要存在該函數必定是一個生成器調用該函數返回一個生成器讓一個生成器前進使用使一個生成器前進到下一個語句處,并將產出值作為其返回值。

前言

這篇文章大部分來自 David Beazley 在 PyCon 2014 的 PPT 《Generators: The Final Frontier》。這個PPT很長而且非常燒腦,建議在閱讀前應了解 Python 的生成器與攜程相關知識,推薦《流暢的 Python》。

David Beazley 的博客

PPT 下載鏈接

生成器(generator)

使用 yield 來定義一個生成器

def countdown(n):
    while n > 0:
        yield n
        n -= 1
    
c = countdown(10)
c

生成器可用于迭代

for x in countdown(10):
    print("倒數:", x)
倒數: 10
倒數: 9
倒數: 8
倒數: 7
倒數: 6
倒數: 5
倒數: 4
倒數: 3
倒數: 2
倒數: 1

可以通過 next() 來一步步地讓生成器 yield 一個值,直到函數迭代器結束并拋出 StopIteration。如果你對這一頭霧水,建議閱讀《Fluent Python》14.4 章。
這里 for 其實相當于不斷地調用 next 并處理 StopIteration

c = countdown(3)

# next(c)
3
# next(c)
2
# next(c)
1
把生成器當作管道

你可以嵌套生成器,這會導致類似于 Unix 命令行管道的效果

def add_A(seq):
    for item in seq:
        yield item + "-A"

def add_B(seq):
    for item in seq:
        yield item + "-B"

def add_C(seq):
    for item in seq:
        yield item + "-C"
        
seq = ["apple", "banana", "orange"]

stacked_generator = add_C(add_B(add_A(seq)))

for item in stacked_generator:
    print(item)
apple-A-B-C
banana-A-B-C
orange-A-B-C

可以看到,我們為 seq 里的每項都依次添加了一個 tag。

yield 可以接受傳值

yield 的作用是向調用者返回一個值,調用者其實也可以向生成器傳值。

def receiver():
    while True:
        received_item = yield
        print("收到:", received_item)

def caller():
    recv = receiver()
    next(recv) # 使生成器前進到 yield
    for i in "abcd":
        recv.send(i)
        
caller()
收到: a
收到: b
收到: c
收到: d

send 函數的返回值是什么呢?

def receiver():
    call_times = 0
    while True:
        item = yield call_times
        print("收到:", item)
        call_times += 1
        
def caller():
    recv = receiver()
    next(recv)
    for i in "abcd":
        ret_value = recv.send(i)
        print("返回值: ", ret_value)
        
caller()
收到: a
返回值:  1
收到: b
返回值:  2
收到: c
返回值:  3
收到: d
返回值:  4

所以 send 可以向生成器傳值的同時會讓生成器前進到下一個 yield 語句,并將 yield 右側的值作為返回值。

生成器 101

yield 用于定義生成器函數

只要 yield 存在該函數必定是一個生成器

調用該函數返回一個生成器

讓一個生成器前進

使用 next 使一個生成器前進到下一個 yield 語句處,并將產出值(yielded value)作為其返回值。使用 gen.__next__()效果相同。

注意:這是一個新創建的生成器唯一允許的操作。

def generator():
    yield "a"
    yield "b"
    
gen = generator()

# next(gen)
"a"
# next(gen)
"b"
給生成器傳值

可以通過調用生成器的 send 方法來向生成器傳值,這將讓生成器從上次暫停的 yield 前進到下個 yield,并將產出值作為 send 的返回值。

def generator():
    item = yield "a"
    print(item)
    another_item = yield "b"
    
gen = generator()
print(next(gen))
print(gen.send(1))
a
1
b
關閉一個生成器

通過調用生成器 close 方法可以生成器在 yield 語句處拋出 GeneratorExit。這時僅允許 return,如果沒有捕捉這個錯誤,生成器會靜默關閉,不拋出錯誤。

def generator():
    times = 0
    while True:
        yield times
        times += 1
            
gen = generator()
print(next(gen))
print(next(gen))
gen.close() # 不會拋出錯誤
0
1
拋出錯誤

調用生成器的 throw 方法可以在 yield 處拋出某個特定類型的錯誤,如果生成器內部可以捕捉這個錯誤,那生成器將前進到下個 yield 語句處,并將產出值作為 throw 的返回值,否則中止生成器。
throw 的函數簽名如下:

throw(typ, [,val, [,tb]])

其中 tyb 是某錯誤類型,val是錯誤信息,tb 為 traceback。更多信息可以參考官方的PEP0342

def generator():
    try:
        yield "apple"
    except RuntimeError as e:
        print("捕捉到:", e)
    yield "banana"
    

gen = generator()
print(next(gen))
print(gen.throw(RuntimeError, "運行錯誤"))
apple
捕捉到: 運行錯誤
banana
生成器返回值

如果在生成器函數中加上 return 那在運行到 return 時將會把返回值作為 StopIteration 的值傳遞出去。這個是 Python3 的特性,Python2 生成器不能返回某個值。

def generator():
    yield
    return "apple"
    
g = generator()
next(g)
try:
    next(g)
except StopIteration as e:
    print(e)
apple
生成器委托

使用 yield from 可以幫你對一個生成器不斷調用 next 函數,并返回生成器的返回值。言下之意是你可以在生成器里調用生成器

def generator():
    yield "a"
    yield "b"
    return "c"
    
def func():
    result = yield from generator()
    print(result)

調用 func 結果是返回一個生成器

# func()


# next(func())
"a"

另外一個例子

def chain(x, y):
    yield from x
    yield from y
    
a = [1, 2, 3]
b = [4, 5, 6]

for i in chain(a, b):
    print(i, end=" ")
1 2 3 4 5 6 
c = [7, 8, 9]
for i in chain(a, chain(b, c)):
    print(i, end=" ")
1 2 3 4 5 6 7 8 9 
Part 1總結 生成器定義
def generator():
    ...
    yield
    ...
    return result
生成器操作
gen = generator()

# 使一個生成器前進
next(gen)

# 傳遞一個值
gen.send(item)

# 中止生成器
gen.close()

# 拋出錯誤
gen.throw(exc, val, tb)

# 委托
result = yield from gen

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/41954.html

相關文章

  • 成器進化協程 Part 2

    摘要:一個典型的上下文管理器類如下處理異常正如方法名明確告訴我們的,方法負責進入上下的準備工作,如果有需要可以返回一個值,這個值將會被賦值給中的。總結都是關于上下文管理器的內容,與協程關系不大。 Part 1 傳送門 David Beazley 的博客 PPT 下載地址 在 Part 1 我們已經介紹了生成器的定義和生成器的操作,現在讓我們開始使用生成器。Part 2 主要描述了如...

    fuyi501 評論0 收藏0
  • PHP回顧之協程

    摘要:本文先回顧生成器,然后過渡到協程編程。其作用主要體現在三個方面數據生成生產者,通過返回數據數據消費消費者,消費傳來的數據實現協程。解決回調地獄的方式主要有兩種和協程。重點應當關注控制權轉讓的時機,以及協程的運作方式。 轉載請注明文章出處: https://tlanyan.me/php-review... PHP回顧系列目錄 PHP基礎 web請求 cookie web響應 sess...

    Java3y 評論0 收藏0
  • tornado 源碼之 coroutine 分析

    摘要:源碼之分析的協程原理分析版本為支持異步,實現了一個協程庫。提供了回調函數注冊當異步事件完成后,調用注冊的回調中間結果保存結束結果返回等功能注冊回調函數,當被解決時,改回調函數被調用。相當于喚醒已經處于狀態的父協程,通過回調函數,再執行。 tornado 源碼之 coroutine 分析 tornado 的協程原理分析 版本:4.3.0 為支持異步,tornado 實現了一個協程庫。 ...

    NicolasHe 評論0 收藏0
  • PyTips 0x13 - Python 線程與協程(2)

    摘要:項目地址我之前翻譯了協程原理這篇文章之后嘗試用了模式下的協程進行異步開發,確實感受到協程所帶來的好處至少是語法上的。 項目地址:https://git.io/pytips 我之前翻譯了Python 3.5 協程原理這篇文章之后嘗試用了 Tornado + Motor 模式下的協程進行異步開發,確實感受到協程所帶來的好處(至少是語法上的:D)。至于協程的 async/await 語法是如...

    史占廣 評論0 收藏0
  • 圖文 視頻雙管齊下,帶你全面徹底理解Retrofit源碼,Android開發五年

    摘要:協程的判斷條件下面我們來著重看下的源碼,因為從這里開始就涉及到協程的判斷。第二點是關鍵點,用來判斷該方法的調用是否使用到了協程。原理我們先來看下使用協程是怎么寫的這是一個標準的協程寫法,然后我們再套用上面的條件,發現完全匹配不到。 第一眼看,跟我之前印象中的有點區別(也不知道是什么版本),return的時候居然...

    不知名網友 評論0 收藏0

發表評論

0條評論

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