
關鍵字 (keyword) yield 用在函數中對呼叫方產生數值,這是說函數 (function) 若使用 yield 產生數值的話,函數會回傳一個產生器 (generator) 物件 (object) ,可由 __next__() 方法 (method) 或內建函數 (built-in function) next() 依序取得 yield 產生的數值,注意 __next__() 方法前後被兩條底線包圍。這樣的執行方式,就好像呼叫函數後,函數並不會立即直接結束,而是與呼叫方同時執行的。
先來看個簡單的例子,函數 yield5() 只有簡單利用關鍵字 yield 產生整數 5 ,變數 (variable) a 會取得 yield5() 回傳的產生器物件,然後利用內建函數 next() 先取得變數 a 產生的第一個數值,就是整數 5 ,再用 next() 一次,結果發生 StopIteration 的錯誤,因為變數 a 中已經沒有數值可以產生了
def yield5():
yield 5
a = yield5()
print(next(a))
print(next(a))
#《程式語言教學誌》的範例程式
# http://kaiching.org/
# 檔名:yield01.py
# 功能:示範 yield 運算
# 作者:張凱慶
於命令列執行以上程式,結果如下
| $ python3 yield01.py |
| 5 |
| Traceback (most recent call last): |
| File "yield01.py", line 6, in <module> |
| print(next(a)) |
| StopIteration |
| $ |
再來用 new_range() 簡單模擬內建函數 range() 的效果,此例變數 b 會是具有從 0 到 9 的產生器物件,這邊用內建函數 next() 取得變數 b 產生的整數兩次
def new_range(n):
i = 0
while i < n:
yield i
i += 1
b = new_range(10)
print(next(b))
print(next(b))
#《程式語言教學誌》的範例程式
# http://kaiching.org/
# 檔名:yield02.py
# 功能:示範 yield 運算
# 作者:張凱慶
於命令列執行以上程式,結果如下
| $ python3 yield02.py |
| 0 |
| 1 |
| $ |
用 for 迴圈 (loop) 可以印出 new_range() 產生的所有整數,例如
def new_range(n):
i = 0
while i < n:
yield i
i += 1
for i in new_range(10):
print(i)
#《程式語言教學誌》的範例程式
# http://kaiching.org/
# 檔名:yield03.py
# 功能:示範 yield 運算
# 作者:張凱慶
於命令列執行以上程式,結果如下
| $ python3 yield03.py |
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| $ |
關鍵字 return 是在函數中回傳數值, return 跟 yield 的作用完全不同, return 後接的回傳值就是給呼叫方的物件,回傳值 (return value) 是什麼型態,呼叫方就得到什麼型態的物件,例如這裡定義了 fib() 函數,這是用來計算費氏數列的函數,結果回傳串列 (list) ,費氏數列則儲存在串列之中。
def fib(n):
L = []
i, a, b = 0, 0, 1
while i < n:
L.append(b)
a, b = b, a + b
i += 1
return L
print(fib(10))
#《程式語言教學誌》的範例程式
# http://kaiching.org/
# 檔名:yield04.py
# 功能:示範 yield 運算
# 作者:張凱慶
於命令列執行以上程式,結果如下
| $ python3 yield04.py |
| [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] |
| $ |
那函數用 return 跟 yield 有什麼不同呢?這裡的 fib2() 函數用 yield 產生費氏數列,相同參數得到的結果跟 fib() 一樣,差別是 fib2() 回傳的是產生器物件,而非串列,利用產生器物件的好處是節省記憶體空間,並且提升程式執行的效率,這優點在資料量極少的情況下看不出來,可是一旦資料量暴增,例如串列中需要儲存數十到數百萬筆資料的時候,相對產生器物件需要的記憶體空間就相當少,所以當資料是依序計算取得的話,利用產生器物件就比較適合
def fib2(n):
i, a, b = 0, 0, 1
while True:
if n <= 0 or i == n:
break
a, b = b, a + b
yield a
i += 1
d = fib2(10)
for i in d:
print(i)
#《程式語言教學誌》的範例程式
# http://kaiching.org/
# 檔名:yield05.py
# 功能:示範 yield 運算
# 作者:張凱慶
於命令列執行以上程式,結果如下
| $ python3 yield05.py |
| 1 |
| 1 |
| 2 |
| 3 |
| 5 |
| 8 |
| 13 |
| 21 |
| 34 |
| 55 |
| $ |
相關教學影片
