Python 生成器,協程

生成器generator

    生成器可以簡單有效的創建龐大的可迭代對象,而不需要在直接在內存中創建存儲整個序列

        可以使用生成器推導式或者生成器函數來創建生成器

        生成器函數返回數據時使用yield語句,而不是使用return

>>> def countdown(n):
...     print("Counting down from %d" %n)
...     while n>0:
...             yield n
...             n -=1
...     return 'done'
...
>>> c = countdown(10)    #c爲一個生成器對象

   

    可以通過next()函數或者生成器對象的__next__()方法來獲得生成器的下一個返回值

    當計算到最後一個元素後,沒有更多的元素時,拋出StopInteration,生成器終止

>>> c = countdown(3)
>>> next(c)
Counting down from 3
3
>>> c.__next__()
2
>>> next(c)
1
>>> next(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration: done

    通常直接通過for循環來迭代生成器,並且不需要關心StopInteration

    但是用for循環調用生成器時,發現拿不到生成器的return語句的返回值。

    如果想要拿到返回值,必須捕獲StopInteration錯誤,返回值包含在StopInteration的value中

>>> while True:
...     try:
...         x = next(c)
...         print(c)
...     except StopIteration as e:
...         print('Generator return value:', e.value)
...         break
...

    當一個生成器沒有全部迭代完成,但是不在使用了,可以調用close()方法關閉生成器,通常不必手動調用close()方法

c = countdown(10)
>>> next(c)
1
>>> c.close()
>>> next(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration


協程

         協程可以理解爲就像生成器那樣可以暫停的函數


    在函數內,當yield語句作爲表達式使用,出現在賦值運算符的右邊,在向函數發送值時函數將執行

    這種生成器函數可以被稱爲協程函數,而對協程函數的調用可以獲得協程對象

"協程"一詞可以用於協程函數和協程對象

>>> def coroutine():
...     print("Start Coroutine")
...     r = 'ok'
...     while True:
...             n = yield r
...             print('receiver %s' % n)
...
>>> c = coroutine()
>>> c.send(1)    
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't send non-None value to a just-started generator
>>> c.send(None)    #next(c)
Start Coroutine
'ok'
>>> c.send(1)
receiver 1
'ok'
>>> c.close()
>>> c.send(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

        在發送數據之前,應該調用c.send(None)啓動生成器或者使用next()函數,使協程執行第一個yield之前的語句

        啓動後協程會掛起,等待協程對象c的send()方法發送值

        yield語句會接收send()發送的值,並返回yield 語句後的值

        協程一般會不斷執行下去,可以通過close()方法關閉協程


我們可以使用asyncio模塊中的@asyncio.coroutine裝飾器來使協程函數在調用時自動運行到yield語句前,而不需要提前調用send(None)或next()函數

具體的asyncio模塊和協程的講解可以看另一篇文章


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章