国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

啊哈,yield

2019-11-14 17:27:46
字體:
來源:轉載
供稿:網友

文章出處:http://m.survivalescaperooms.com/winstic/,請保留此連接

在python編程中,我們經常會看到函數中帶有yield關鍵字,但請注意,此時的函數不再是我們熟知的一般函數,而是所謂的generator(生成器)


  

生成器

  對于生成器,可以對比于列表來看,我們在循環代碼中經常會使用range()產生一個list對象,繼而在for循環下依次遍歷,

for i in range(1000):    PRint i

  或者是使用列表生成式生成一個list對象:

[x * x for x in range(1000)]

  這么做確實很方便,但這有個很大的缺點,我們所生產的list對象在程序運行過程中是存放在內存中的,占用內存大小與list規模有關,若要在編程時控制內存的占用,最好不要使用list。

 

  相比于list對象對內存的占用,generator有很大的優勢,generator保存的是算法,不會生成所有的元素,而只是在調用next()時產生一個元素,很好的優化了內存占用的問題,可以通過next方法訪問數據,當沒有數據時會自動拋出StopIteration異常

>>> gener = (x * x for x in [1, 2, 3])>>> g = (x * x for x in [1, 2, 3])>>> g<generator object <genexpr> at 0x02534968>>>> g.next()1>>> g.next()4>>> g.next()9>>> g.next()Traceback (most recent call last):  File "<pyshell#16>", line 1, in <module>    g.next()StopIteration>>> 

  這么做的話難免有些繁瑣,還好在for循環中會幫我們實現next方法的調用也可以這么實現

>>> for i in g:    print i

 


 

yield 初體驗

  以上所實現的generator只是規律十分簡單的,這很好實現,只需要類似于列表生成式的簡單語法即可,那么對于其他的數列計算如何實現呢,例如斐波那契數列,它的定義雖然簡單:除第一、二個數據外,所有的數據均是其前兩個數據之和;如果我們通過一般函數實現,無疑當數列規模很大時,占用大量內存

>>> def fib(N):    n, a, b = 0, 0, 1    while n < N:        print b        a, b = b, a + b        n = n + 1

  那么如何將上述方法轉換為generator加以實現呢,很簡單,只需要將print b 替換為yield b即可,我們可以試一下:

>>> def fib(N):    n, a, b = 0, 0, 1    while n < N:        yield b        a, b = b, a + b        n = n + 1        >>> fib(5)<generator object fib at 0x02530F80>>>> for i in fib(5):    print i    11235

 

  加了yield關鍵字后的函數是如何執行的呢,不應該說是函數,這時應該稱為generator;我們調用fib(5)并不會執行函數,而是返回一個generator對象,真正的執行是在調用next方法(for循環中自動調用next()),每次循環都會執行fib內的代碼,遇到yield則返回一個迭代值(類似于中斷);在下次循環時執行yield的下一語句,直至遇到下一個yield。

 

 


 

yield 協程

 

  協程(coroutine)也叫微線程,相比于多線程更為高效,因為協程是多個程序在一個線程中執行,沒有線程間切換的開銷;同時在協程中不需要加鎖機制,因為在一個線程中不存在變量沖突問題。

  例如經典問題(生產者-消費者問題)就可以使用協程機制實現,相比于多線程更為高效

def consumer():    r = ''    while True:        n = yield r        if not n:            return        print 'consumer %s' % n        r = 'OK'def produce(c):    c.next()    n = 0    while n < 5:        n = n + 1        print 'produce %s' % n        r = c.send(n)        print 'consumer return %s' % r    c.close()if __name__ == '__main__':    c = consumer()    produce(c)

 

produce 1consumer 1consumer return OKproduce 2consumer 2consumer return OKproduce 3consumer 3consumer return OKproduce 4consumer 4consumer return OKproduce 5consumer 5consumer return OK
執行結果

  在上述代碼中,consumer是一個生成器,執行過程中首先通過consumer產生generator對象c,

  我們在執行到produce(c)的next方法時,才切換到生成器函數consumer中執行,

  在consumer中遇到yield中斷,又切回到produce中

  在produce中的c.send(n):主要干兩件事:1.將n添加到生成器中,2.返回下一個yield值(return next());所以當我們運行到send方法時,內含next機制進而切換到consumer函數中執行(傳入參數n),得到返回值'OK'(在下一個yield中返回)

  。。。。。

  最后在produce中關閉迭代器c.close()

 

參考:         http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0013868328689835ecd883d910145dfa8227b539725e5ed000


 

總結:

  1. 在generator中不同于一般函數,調用方法名不會執行,只會返回一個generator對象,只有在調用next方法時才會執行
  2. 一個函數中加入yield則變為generator,函數執行到yield時中斷,下次迭代時定位到yield的下一條語句;yield還常用于文件的讀取,用read()會造成不可預測的內存占用問題,而使用yield可以實現內存只存儲每次迭代過程中固定的size

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 龙游县| 新泰市| 容城县| 桂林市| 楚雄市| 娄烦县| 潼南县| 杨浦区| 双鸭山市| 镇远县| 桦川县| 应城市| 布拖县| 毕节市| 萍乡市| 朝阳市| 海丰县| 淮阳县| 吉隆县| 武川县| 中山市| 措美县| 黄骅市| 中牟县| 崇阳县| 南投县| 岑巩县| 和田市| 墨竹工卡县| 乡城县| 德钦县| 酉阳| 铜川市| 茌平县| 乳源| 浮梁县| 兴山县| 宜州市| 水城县| 白水县| 全州县|