關鍵字 (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 |
$ |
相關教學影片