二、生成器
說迭代器之前有兩個相關的名詞需要介紹:
可迭代物件:只要定義了__iter__()方法,我們就說該物件是可迭代物件,並且可迭代物件能提供迭代器。
迭代器:實現了__next__()或者next()(python2)方法的稱為迭代器,迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之後,元素可以不存在或者被銷毀,因此只占用固定的記憶體。
迭代:當我們使用乙個迴圈來遍歷某個東西時,這個過程本身就叫迭代。迭代器迭代的元素只能往前不能後退。
下面用生成斐波那契數列為例子,說明為何用迭代器
#**1
deffab
(max):
n, a, b =0,
0,1while n <
max:
print b
a, b = b, a + b
n = n +
1#直接在函式fab(max)中用print列印會導致函式的可復用性變差,因為fab返回none。其他函式無法獲得fab函式返回的數列。
#**2
deffab
(max):
l =n, a, b =0,
0,1while n <
max:
a, b = b, a + b
n = n +
1return l
#**2滿足了可復用性的需求,但是占用了記憶體空間。
#**3,定義並使用迭代器
class
fab(
object):
def__init__
(self,
max)
: self.
max=
max
self.n, self.a, self.b =0,
0,1def
__iter__
(self)
:return self
defnext
(self)
:if self.n < self.
max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n +
1return r
raise stopiteration(
)for key in fabs(5)
:print key
#fabs 類通過 next() 不斷返回數列的下乙個數,記憶體占用始終為常數
使用內建的工廠函式iter(iterable)可以獲取迭代器物件(物件包含__iter__方法即可迭代,__iter__方法返回乙個迭代器):
>>
> lst =
range(5
)>>
> it =
iter
(lst)
>>
> it
>
使用next()方法訪問下乙個元素
>>
> it.
next()
0>>
> it.
next()
1>>
> it.
next()
2
python處理迭代器越界是丟擲stopiteration異常
>>
> it.
next()
3>>
> it.
next
>
>>
> it.
next()
4>>
> it.
next()
traceback (most recent call last)
:file ""
, line 1,in
stopiteration
了解了stopiteration,可以使用迭代器進行遍歷了:
lst =
range(5
)it =
iter
(lst)
try:
while
true
: val = it.
next()
print val
except stopiteration:
pass
幸運的是python提供的for語句語法糖為迭代提供了方便的使用方法。在for迴圈中,python將自動呼叫工廠函式iter()獲得迭代器,自動呼叫next()獲取元素,還完成了檢查stopiteration異常的工作。
>>
> lst =
range(5
)>>
>
for i in lst:..
.print i..
.012
34
帶有 yield 的函式在 python 中被稱之為 generator(生成器),幾個例子說明下(還是用生成斐波那契數列說明),可以看出**3遠沒有**1簡潔,生成器(yield)既可以保持**1的簡潔性,又可以保持**3的效果。
#**4
deffab
(max):
n, a, b =0,
0,1while n <
max:
yield b
a, b = b, a + b
n = n+
1#執行
for n in fab(5)
:print n
生成器也是一種迭代器,簡單地講,yield 的作用就是把乙個函式變成乙個 generator,帶有 yield 的函式不再是乙個普通函式,python 直譯器會將其視為乙個 generator,呼叫 fab(5) 不會執行 fab 函式,而是返回乙個 iterable 物件!在 for 迴圈執行時,每次迴圈都會執行 fab 函式內部的**,執行到 yield b 時,fab 函式就返回乙個迭代值,下次迭代時,**從 yield b 的下一條語句繼續執行,而函式的本地變數看起來和上次中斷執行前是完全一樣的,於是函式繼續執行,直到再次遇到 yield。看起來就好像乙個函式在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 返回當前的迭代值。
也可以手動呼叫 fab(5) 的 next() 方法(因為 fab(5) 是乙個 generator 物件,該物件具有 next() 方法),這樣我們就可以更清楚地看到 fab 的執行流程:
>>
> f = fab(3)
>>
> f.
next()
1>>
> f.
next()
1>>
> f.
next()
2>>
> f.
next()
traceback (most recent call last)
:file ""
, line 1,in
stopiteration
在乙個生成器中,如果沒有return,則預設執行到函式完畢;如果遇到return,如果在執行過程中 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,我們不再需要編寫讀檔案的迭代類,就可以輕鬆實現檔案讀取。 python 迭代器,生成器詳解。
任何實現了 iter 和 next python2中實現next 方法的物件都是迭代器 迭代器可以被next 函式呼叫並不斷返回下乙個值的,或者使用for迴圈。因為python的for迴圈本質上就是通過不斷呼叫next 函式實現的。for 迴圈在處理這些資料前,會呼叫 iter 方法,將這些資料轉化...
Python迭代器和生成器
先說迭代器,對於string list dict tuple等這類容器物件,使用for迴圈遍歷是很方便的。在後台for語句對容器物件呼叫iter 函式,iter 是python的內建函式。iter 會返回乙個定義了next 方法的迭代器物件,它在容器中逐個訪問容器內元素,next 也是python的...
Python迭代器和生成器
迭代器是訪問集合元素的一種方法 是可以記住遍歷的位置的物件。迭代器物件從集合的第乙個元素開始訪問,直到所有的元素被訪問 他有兩個基本的方法,iter 和next 字串,列表或遠足物件都可以用於建立迭代器 list1 1,2,3,4 it1 iter list1 建立迭代器物件 print next ...