Python 迭代器 生成器

2021-07-24 13:17:41 字數 3815 閱讀 7779

可以直接作用於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...