python 迭代器和生成器詳解

2021-09-25 11:42:53 字數 4072 閱讀 6903

二、生成器

說迭代器之前有兩個相關的名詞需要介紹:

可迭代物件:只要定義了__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 ...