事實上,yield 和 return 很像,只是當函數呼叫 return 時,該函數 call stack (python 中是 frame) 就會被清除,程式主導權回到呼叫該函數的手上。 而 yield 會把程式主導權交給呼叫該函數的手上,但是他不會把函數的 call stack 清除,因此下次呼叫時,可以從上次未執行的部分開始執行,而不是重新建立一個新 stack。
def return_fun(): a = 1 b = 1 return a print return_fun() print return_fun()
上面這段程式碼,每次呼叫 return_fun 時,都是從 a = 1 開始執行,然後遇到 return 就結束了。所以執行流程像這樣
當有函數裡面有用到 yield 這個關鍵字時,事情就變得很不一樣了。
def yield_fun(): a = 1 b = 1 yield a
yield b print yield_fun()
當你執行上面這段程式碼時,你會發現他回傳給你的居然是 generator 物件。那要怎麼執行 yield_fun 裡面的 code 呢? 答案是使用 generator 的 next 方法。
def yield_fun(): a = 3 b = 2 yield a c = 4 yield b generator = yield_fun() print generator.next() print generator.next()
當使用者第一次呼叫 generator 的 next 方法時,他會從 a = 3 開始執行,直到遇到 yield。python 會回傳 yield 後面接的東西(就像 return ),之後再把現在的 call stack( python 中是 frame),儲存在 generator 的 gi_frame 屬性中。
當使用者第二次呼叫 generator 的 next 方法時,他不會建立一個新的 call stack,而是從 generator 的 gi_frame 屬性中取出之前的 call stack。因此,程式會從 c = 4 開始執行(不是從 a = 3喔,如果是 function 的話,是從 a = 3 開始執行)。直到遇到 yield 或是 return 為止。遇到 yield 表示下次還可以再呼叫一次 next 方法。遇到 return 則表示 這個 generator 已經沒東西了。無法再呼叫 next 了。執行流程像這樣。
事實上, yield 除了可以把資料回傳給呼叫者外,他也可以從呼叫者接受資料。向下面的程式碼。
def yield_fun(): a = 3 b = 2 b = yield a yield b generator = yield_fun() print generator.next() print generator.send(8)
上面這段程式碼, yield 除了把 a 的值回傳給呼叫者外,他還會從呼叫者那邊接受一個值,把 b 的值指派成呼叫者給的參數。
generator 打破函數執行完後, call stack 就會被清除的限制(因為 generator 把 call stack 存在 gi_frame 屬性,所以下次執行時,還知道之前的狀態)。
I like your blog, I read this blog please update more content on hacking, further check it once at python online course
回覆刪除請問有Python3的內容嗎?因為Python3的運作方式已經不一樣了。
回覆刪除def yield_fun():
刪除a = 3
b = 2
b = yield a
yield b
generator = yield_fun()
print(next(generator))
print(generator.send(8))
最清楚明白的說明
回覆刪除