可以直接作用於for迴圈的物件,統稱為可迭代物件:iterable。
iterator物件表示的是乙個資料流,iterator物件可以被next()函式呼叫並不斷返回下乙個資料,直到沒有資料時丟擲stopiteration錯誤。可以把這個資料流看做是乙個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()函式實現按需計算下乙個資料,所以iterator的計算是惰性的,只有在需要返回下乙個資料時它才會計算。
iterator甚至可以表示乙個無限大的資料流,例如全體自然數。而使用list是永遠不可能儲存全體自然數的。
迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之後,元素可以不存在或者被銷毀。這個特點使得它特別適合用於遍歷一些巨大的或是無限的集合,比如幾個g的檔案,或是斐波那契數列等等。
與一般的序列型別(list, tuple等)有什麼區別:
它一次只返回乙個資料項,占用更少的記憶體。
但它需要記住當前的狀態,以便返回下一資料項。它是乙個有著next()方法的物件。
而序列型別則儲存了所有的資料項,它們的訪問是通過索引進行的。
對於原生支援隨機訪問的資料結構(如tuple、list),迭代器和經典for迴圈的索引訪問相比並無優勢,反而丟失了索引值(可以使用內建函式enumerate()找回這個索引值)。
迭代器有兩個基本的方法
__iter__方法:返回迭代器物件本身
迭代器:僅是一容器物件,它實現了迭代器協議。
下面用生成斐波那契數列為例子,說明為何用迭代器。
def fab(max):
n, a, b = 0, 0, 1
while n < max:
print b
a, b = b, a + b
n = n + 1
直接在函式fab(max)中用print列印會導致函式的可復用性變差,因為fab返回none。其他函式無法獲得fab函式返回的數列。
def fab(max):
l =
n, a, b = 0, 0, 1
while n < max:
a, b = b, a + b
n = n + 1
return l
滿足了可復用性的需求,但是占用了記憶體空間,最好不要。
class fab(object):
def __init__(self, max):
self.max = max
self.n, self.a, self.b = 0, 0, 1
def __iter__(self):
return self
def next(self):
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
raise stopiteration
>>> for key in fabs(5):
print key11
235fabs 類通過 next() 不斷返回數列的下乙個數,記憶體占用始終為常數
帶有 yield 的函式在 python 中被稱之為 generator(生成器),幾個例子說明下(還是用生成斐波那契數列說明)
可以看出**3遠沒有**1簡潔,生成器(yield)既可以保持**1的簡潔性,又可以保持**3的效果
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
>>> for n in fab(5):
print n11
235yield 的作用就是把乙個函式變成乙個 generator。
帶有 yield 的函式不再是乙個普通函式,python 直譯器會將其視為乙個 generator。
呼叫 fab(5) 不會執行 fab 函式,而是返回乙個 iterable 物件!
在 for 迴圈執行時,每次迴圈都會執行 fab 函式內部的**,執行到 yield b 時,fab 函式就返回乙個迭代值,下次迭代時,**從 yield b 的下一條語句繼續執行,而函式的本地變數看起來和上次中斷執行前是完全一樣的,於是函式繼續執行,直到再次遇到 yield。看起來就好像乙個函式在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 返回當前的迭代值。
如果在執行過程中 return,則直接丟擲 stopiteration 終止迭代。
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
如果直接對檔案物件呼叫 read() 方法,會導致不可**的記憶體占用。
好的方法是利用固定長度的緩衝區來不斷讀取檔案內容。通過 yield,我們不再需要編寫讀檔案的迭代類,就可以輕鬆實現檔案讀取。
判斷乙個函式是否是乙個特殊的 generator 函式
>>> from inspect import isgeneratorfunction
>>> isgeneratorfunction(fab)
true
要注意區分 fab 和 fab(5),fab 是乙個 generator function,而 fab(5) 是呼叫 fab 返回的乙個 generator,好比類的定義和類的例項的區別:
>>> import types
>>> isinstance(fab, types.generatortype)
false
>>> isinstance(fab(5), types.generatortype)
true
fab 是無法迭代的,而 fab(5) 是可迭代的:
>>> from collections import iterable
>>> isinstance(fab, iterable)
false
>>> isinstance(fab(5), iterable)
true
使用isinstance()判斷乙個物件是否是iterable物件:
>>> from collections import iterable
>>> isinstance(, iterable)
true>>> isinstance({}, iterable)
true>>> isinstance('abc', iterable)
true>>> isinstance((x for x in range(10)), iterable)
true>>> isinstance(100, iterable)
false
使用isinstance()判斷乙個物件是否是iterator物件:
>>> from collections import iterator
>>> isinstance((x for x in range(10)), iterator) #是(x for x in range(10))不是[x for x in range(10)]
true>>> isinstance(, iterator)
false>>> isinstance({}, iterator)
false>>> isinstance('abc', iterator)
false
python 迭代器,生成器
什麼事迭代 可直接用作與for迴圈的物件統稱為可迭代物件 可以被next 函式呼叫,並不斷返回下乙個值的物件稱為迭代器,所有的iterable均可以通過內建函式iter 來轉變為iterator。對於迭代器來講,有乙個next 就夠了。在你使用for和in語句時,程式就會自動呼叫即將被處理的物件的可...
python 迭代器 生成器
知識背景 1 呼叫乙個普通的python函式時,一般是從函式的第一行 開始執行,結束於return語句 異常或者函式結束 可以看作隱式的返回none 2 一旦函式將控制權交還給呼叫者,就意味著全部結束。函式中做的所有工作以及儲存在區域性變數中的資料都將丟失 3 再次呼叫這個函式時,一切都將從頭建立。...
python 迭代器,生成器
以直接作用於 for 迴圈的資料型別有以下幾種 一類是集合資料型別,如 list tuple dict set str 等 一類是 generator 包括生成器和帶 yield 的generator function 這些可以直接作用於 for 迴圈的物件統稱為可迭代物件 iterable pyt...