在python中,帶yield的函式稱為生成器(generator),python對協程的支援也是通過生成器實現的。
yield
首先將yield當成乙個斷點標記,中斷,return 。當程式執行到yield處,返回yield後邊的變數,中斷。其他程式獲取這個變數,呼叫生成器的next()函式,程式又回到生成器,接著向下執行。
乙個帶有 yield 的函式就是乙個 generator,它和普通函式不同,生成乙個 generator 看起來像函式呼叫,但不會執行任何函式**,直到對其呼叫 next()(在 for 迴圈中會自動呼叫 next())才開始執行。雖然執行流程仍按函式的流程執行,但每執行到乙個 yield 語句就會中斷,並返回乙個迭代值,下次執行時從 yield 的下乙個語句繼續執行。看起來就好像乙個函式在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 返回當前的迭代值。
def
foo():
print
("starting..."
)while
true
: res =
yield
4print
("res:"
,res)
g = foo(
)print
(next
(g))
print
("*"*20
)print
(next
(g))
執行結果
starting...
4******
****
****
****
**res:
none
4
1首先foo函式含有yield,是乙個生成器,g = foo(),並不執行foo()函式,而是返回乙個迭代器物件賦值給g。
2 呼叫迭代器物件g的next()方法,foo函式開始執行,列印"starting…",進入while迴圈,執行到yield,中斷,return後邊的變數4,程式跳轉回到print(next(g))。即print(yield返回的變數4)。
3 順序執行print("*"*20)。
4 再次呼叫迭代器物件g的next()方法,程式跳轉到上次next結束的地方,即res賦值操作,因為變數4被return出去了,所以res賦值為空。執行print(「res:」,res),即列印res: none,繼續迴圈到yield,再次中斷,return 後邊的變數4,然後跳轉到print(next(g)),即列印4。
生成器有乙個重要的方法next(),呼叫next(),程式從上次next()停止的地方開始執行,直至遇到yield,返回後面的變數,此步停止。
send例子
send(value)
迭代器物件的send方法,傳送乙個值value給生成器,並返回下乙個yield的值(也就行呼叫next()方法)。
def
foo():
print
("starting..."
)while
true
: res =
yield
4print
("res:"
,res)
g = foo(
)print
(next
(g))
print
("*"*20
)print
(g.send(7)
)
結果
starting...
4******
****
****
****
**res:
74
最後一步:g.send(7),回到上次yield結束的地方,即res賦值操作,即把send的值7賦值給res,繼續執行,即列印res,然後執行到yield,返回yield後面的變數4,中斷跳出。回到print(g.send(7)),即列印pirnt(4).
使用生成器可以節省記憶體空間,比如for i in range(1000),則會生成乙個list儲存1000個元素,而for i in xrange(1000),xrange(1000)就是乙個生成器,每次yield 乙個元素。
讀取文字,如果直接讀取,會將文字內容全部載入到記憶體中,占用大量記憶體,而生成器則每次yield固定大小block_size 的文字塊到記憶體。
def
read_file
(fpath)
: block_size =
1024
with
open
(fpath,
'rb'
)as f:
while
true
: block = f.read(block_size)
if block:
yield block
else
:return
send函式和for迴圈都會自動呼叫next()函式。當函式執行結束時,generator 自動丟擲 stopiteration 異常,表示迭代完成。在 for 迴圈裡,無需處理 stopiteration 異常,迴圈會正常結束。
python對協程的支援是通過generator實現的。
在generator中,我們不但可以通過for迴圈來迭代,還可以不斷呼叫next()函式獲取由yield語句返回的下乙個值。但是python的yield不但可以返回乙個值,它還可以接收呼叫者發出的引數。
生產者–消費者模型
def
consumer()
: r =
''while
true
: n =
yield r
ifnot n:
return
print
('[consumer] consuming %s...'
% n)
r ='200 ok'
defproduce
(c):
c.send(
none
)#啟動生成器 想當與next(c)
n =0while n <5:
n = n +
1print
('[producer] producing %s...'
% n)
r = c.send(n)
print
('[producer] consumer return: %s'
% r)
c.close(
)c = consumer(
)produce(c)
1 c = consumer(),返回乙個迭代器物件。並不執行consumer,在呼叫next方法才會執行。
2 produce(c )中,c.send(none) 啟動生成器。produce一旦生產了東西,通過 c.send(n)切換到consumer,consumer通過yield拿到東西,經過處理後,有經過下乙個yield返回。pruduce拿到處理的結果,繼續生產下乙個東西。produce決定不生產,通過c.close()關閉consumer,整個過程結束.
python菜鳥學習Day12 裝飾器,列舉類
裝飾器 decorater 當想改變函式的功能,而不改變函式本身定義的時候,就用到了裝飾器。比如,列印函式呼叫的日誌。正常來說在函式中新增print 或者呼叫log包就行。但不想改變函式本身,就需要裝飾器來完成。裝飾器是高階函式,引數是需要列印日誌的函式,返回值也是函式。from functools...
python學習 day12 模組os sys
內容 以下內容僅供個人學習使用,侵刪 usr bin env python coding utf 8 os 通過程式與作業系統做互動 import os 四個維度 重要的 1.資料夾 建立資料夾 os.mkdir,os.makedirs 刪除資料夾 os.rmdir,os.removedirs 檢視...
前端學習Day12
一 定位 1.position static absolute relative 2.position fixed 固定定位 a 參照物 瀏覽器視窗 b 不佔據空間,脫離布局流 3.讓乙個元素在瀏覽器視窗左右上下居中?第一種方法 前提 已知寬和高 position fixed left 50 top...