Python進階編程之產生器(Generator)與coroutine(一):Generator

來源:互聯網
上載者:User

標籤:

這是一系列的文章,會從基礎開始一步步的介紹Python中的Generator以及coroutine(協程)(主要是介紹coroutine),並且詳細的講述了Python中coroutine的各種進階用法,最後會用coroutine實現一個簡單的多任務的作業系統。

其實也是看完這篇文章的學習筆記吧!O(∩_∩)O

產生器(Generator)

什麼是產生器?在Python中,產生器(Generator)是一個帶有yield關鍵字的函數

 1 def gene(): 2     a = 1 3     print "開始執行gene(),a = ",a 4     a += 1 5     yield "rio_2607" 6     print "回到gene(),再辭開始執行,a = ",a 7     a += 2 8     yield "uestc" 9     print "又回到了gene(),a = ",a10     yield "emc"

gene()就是一個產生器,因為函數的定義中有yield關鍵字。那麼產生器跟普通的函數有什麼區別呢?

當調用gene()函數的時候,不會立即執行gene()函數中的代碼,而是返回一個產生器對象(generator object):

 1 >>> def gene(): 2     a = 1 3     print "開始執行gene(),a = ",a 4     a += 1 5     yield "rio_2607" 6     print "回到gene(),再辭開始執行,a = ",a 7     a += 2 8     yield "uestc" 9     print "又回到了gene(),a = ",a10     yield "emc"11 12     13 >>> g = gene()14 >>> type(g)15 <type ‘generator‘>

可以看到,g是一個generator類型的對象。那麼什麼時候會執行函數的代碼呢?答:當調用產生器對象的next()函數時就會開始執行函數定義中的代碼。

但是跟普通函數一旦開始執行就會一直執行直到結束不同,產生器函數會一直往下執行,但是一旦碰到yield關鍵字,就會返回yield關鍵字後面的資料,把函數當前的所有狀態封存起來,然後暫停函數的執行,在產生器對象的next()函數再一次被調用的時候,會接著上一次暫停地方繼續往下執行,直到碰到了下一個yield關鍵字或者函數的代碼執行完畢

>>> g = gene()>>> type(g)<type ‘generator‘>>>> g.next()開始執行gene(),a =  1‘rio_2607‘>>> g.next()回到gene(),再辭開始執行,a =  2‘uestc‘>>> g.next()又回到了gene(),a =  4‘emc‘

可以看到,第一次調用g.next()函數時,函數內部的代碼才開始執行,當執行到yield "rio_2607"這一句代碼時,會返回"rio_2607",然後函數暫停執行。然後當再次調用next函數的時候,gene()函數會接著往下面執行,可以看到,這時列印出來的a=2,保持了函數上一次離開時候的資料,當碰到yield "uestc"這一句時,函數會再次停止執行,封存此時函數內的資料。當再一次調用next()函數的時候,gene()會接著上次的狀態,在上次暫停地方繼續往下執行,可以看到,此時列印輸出了a=4,碰到yield之後再次暫停執行。

當產生器執行完畢後,再一次調用next()時,函數會拋出StopIteration異常

>>> g.next()又回到了gene(),a =  4‘emc‘>>> g.next()Traceback (most recent call last):  File "<pyshell#13>", line 1, in <module>    g.next()StopIteration

產生器運算式(Generator Expresisions)

 產生器運算式(Generator Expresisions)類似於列表推導式(list comprehension)

ge = (x * 2 for x in a)

其中(x * 2 for x in a)就是產生器運算式,這個運算式會返回一個產生器對象:

>>> ge = (x * 2 for x in a)>>> ge<generator object <genexpr> at 0x01EA0A30>

在for迴圈中,for迴圈會自動調用產生器對象的next()函數並處理StopIteration異常:

>>> ge<generator object <genexpr> at 0x01EA0A30>>>> for i in ge:    print i    2468

說了那麼多,那麼產生器除了實現迭代器(Iteration)之外,還有有什麼作用呢?

我們有這麼一個web server上面的log檔案,資料大概是這樣的

77.81.4.30 - - [24/Feb/2008:02:17:53 -0600] "GET /favicon.ico HTTP/1.1" 404 13324.1.247.118 - - [24/Feb/2008:02:20:25 -0600] "GET /dynamic/ HTTP/1.1" 200 510524.1.247.118 - - [24/Feb/2008:02:20:26 -0600] "GET /favicon.ico HTTP/1.1" 404 13324.1.247.118 - - [24/Feb/2008:02:20:26 -0600] "GET /favicon.ico HTTP/1.1" 404 133122.117.168.219 - - [24/Feb/2008:02:22:06 -0600] "GET /ply/ HTTP/1.1" 304 -122.117.168.219 - - [24/Feb/2008:02:22:06 -0600] "GET /ply/bookplug.gif HTTP/1.1" 304 -122.117.168.219 - - [24/Feb/2008:02:22:08 -0600] "GET /ply/example.html HTTP/1.1" 304 -89.182.136.236 - - [24/Feb/2008:02:23:04 -0600] "GET /ply/ HTTP/1.1" 200 801889.182.136.236 - - [24/Feb/2008:02:23:05 -0600] "GET /ply/bookplug.gif HTTP/1.1" 200 2390389.182.136.236 - - [24/Feb/2008:02:23:05 -0600] "GET /favicon.ico HTTP/1.1" 404 13366.249.65.37 - - [24/Feb/2008:02:23:29 -0600] "GET /papers/SIAM97/SIAM97.pdf HTTP/1.1" 200 188949117.198.144.124 - - [24/Feb/2008:02:23:50 -0600] "GET /ply/ply.html HTTP/1.1" 200 97238117.198.144.124 - - [24/Feb/2008:02:23:53 -0600] "GET /favicon.ico HTTP/1.1" 404 133

每一行的最後一列要麼表示一個位元組資料,要麼為-,表示位元組資料未知

現在我們要統計檔案中記錄的所有的位元組資料大小

python中常規的寫法是這樣的,在一個for迴圈中,每次處理一行資料:

 1 def non_generator_func(): 2     ‘‘‘ 3     分析web server的log檔案來判斷所有傳輸的位元組數 4     Non-Generator的寫法:用一個for迴圈 5     :return: 6     ‘‘‘ 7     wwwlog = open("access-log") 8     total = 0 9 10     for line in wwwlog:11         # 擷取位元組數的字串表示12         bytestr = line.rsplit(None, 1)[1]13         if bytestr != "-":14             total += int(bytestr)15 16     print "Total", total

現在來看看使用Generator的風格編寫的代碼:

1 def generator_func():2     wwwlog = open("access-log")3     # 採用產生器運算式(Generator expression),返回一個Generator對象4     bytecolumn = (line.rsplit(None, 1)[1] for line in wwwlog)5     bytes = (int(x) for x in bytecolumn if x != "-")6 7     # 最後一步才進行計算8     print "Total", sum(bytes)

可以看出,使用Generator,可以編寫更少的代碼,還會有跟普通的Python編程完全不一樣的編程風格。

關於Python中的產生器,Python函數式編程指南(四):產生器這篇部落格講的挺好的,大家可以看下這篇部落格。

Python進階編程之產生器(Generator)與coroutine(一):Generator

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.