這一講的主要目的是為了大家在讀 Python 程式的時候對迴圈物件有一個基本概念。
迴圈物件的並不是隨著 Python 的誕生就存在的,但它的發展迅速,特別是 Python 3x 的時代,迴圈物件正在成為迴圈的標準形式。
 
什麼是迴圈物件
迴圈物件是這樣一個物件,它包含有一個 next() 方法 (__next__() 方法,在 python 3x 中), 這個方法的目的是進行到下一個結果,而在結束一系列結果之後,舉出 StopIteration 錯誤。
當一個迴圈結構(比如 for)呼叫回圈物件時,它就會每次迴圈的時候呼叫 next() 方法,直到 StopIteration 出現,for 迴圈接收到,就知道迴圈已經結束,停止呼叫 next() 。
假設我們有一個 test.txt 的檔案:

1234
abcd
efg

我們執行一下 python 命令列:
>>>f = open(‘test.txt’)
>>>f.next()
>>>f.next()

不斷輸入 f.next(),直到最後出現 StopIteration
open() 返回的實際上是一個迴圈物件,包含有 next() 方法。而該 next() 方法每次返回的就是新的一行的內容,到達檔案結尾時舉出 StopIteration 。這樣,我們相當於手工進行了迴圈。
自動進行的話,就是:

for line in open(‘test.txt’):
print line

在這裏,for 結構自動呼叫 next() 方法,將該方法的返回值賦予給 line 。迴圈知道出現 StopIteration 的時候結束。
 
相對於序列,用迴圈物件的好處在於:不用在迴圈還沒有開始的時候,就生成好要使用的元素。所使用的元素可以在迴圈過程中逐次生成。這樣,節省了空間,提高了效率,程式設計更靈活。
 
迭代器
從技術上來説,迴圈物件和 for 迴圈呼叫之間還有一箇中間層,就是要將回圈物件轉換成迭代器 (iterator) 。這一轉換是通過使用 iter() 函式實現的。但從邏輯層面上,常常可以忽略這一層,所以迴圈物件和迭代器常常相互指代對方。
 
生成器
生成器 (generator) 的主要目的是構成一個使用者自定義的迴圈物件。
生成器的編寫方法和函式定義類似,只是在 return 的地方改為 yield 。生成器中可以有多個 yield 。當生成器遇到一個 yield 時,會暫停執行生成器,返回 yield 後面的值。當再次呼叫生成器的時候,會從剛才暫停的地方繼續執行,直到下一個 yield 。生成器自身又構成一個迴圈器,每次迴圈使用一個 yield 返回的值。
 
下面是一個生成器:

def gen():
a = 100
yield a
a = a*8
yield a
yield 1000

該生成器共有三個 yield, 如果用作迴圈器時,會進行三次迴圈。

for i in gen():
print i

 
再考慮如下一個生成器:

def gen():
for i in range(4):
yield i

它又可以寫成生成器表示式 (Generator Expression):

G = (x for x in range(4))

生成器表示式是生成器的一種簡便的編寫方式。讀者可進一步查閲。
 
表推導
表推導 (list comprehension) 是快速生成表的方法。它的語法簡單,很有實用價值。
 
假設我們生成表 L:

L = []
for x in range(10):
L.append(x**2)

以上產生了表 L,但實際上有快捷的寫法,也就是表推導的方式:

L = [x**2 for x in range(10)]

這與生成器表示式類似,只不過用的是中括號。
(表推導的機制實際上是利用迴圈物件,有興趣可以查閲。)
 
練習 下面的表推導會生成什麼?

xl = [1,3,5]
yl = [9,12,13]
L = [ x**2 for (x,y) in zip(xl,yl) if y > 10]

 
總結
迴圈物件
生成器
表推導