Python的迭代器和生成器

2021-09-20 02:47:22 字數 3962 閱讀 1029

先說迭代器,對於stringlistdicttuple等這類容器物件,使用for迴圈遍歷是很方便的。在後台for語句對容器物件呼叫iter()函式,iter()是python的內建函式。iter()會返回乙個定義了next()方法的迭代器物件,它在容器中逐個訪問容器內元素,next()也是python的內建函式。在沒有後續元素時,next()會丟擲乙個stopiteration異常,通知for語句迴圈結束。比如:

>>> s = 'abc'

>>> it = iter(s)

>>> it

>>> next(it)

'a'>>> next(it)

'b'>>> next(it)

'c'>>> next(it)

traceback (most recent call last):

file "", line 1, in stopiteration

上面說的都是python自帶的容器物件,它們都實現了相應的迭代器方法,那如果是自定義類需要遍歷怎麼辦?方法很簡單,對這個類aclass,實現乙個__iter__(self)方法,使其返回乙個帶有__next__(self)方法的物件就可以了。如果你在aclass剛好也定義了__next__(self)方法(一般使用迭代器都會定義),那在__iter__裡只要返回self就可以。廢話少說,先上**:

class fib(object):

def __init__(self, max):

super(fib, self).__init__()

self.max = max

def __iter__(self):

self.a = 0

self.b = 1

return self

def __next__(self):

fib = self.a

if fib > self.max:

raise stopiteration

self.a, self.b = self.b, self.a + self.b

return fib

def main():

fib = fib(100)

for i in fib:

print(i)

if __name__ == '__main__':

main()

簡單講下**會幹什麼,定義了乙個fib類,用於生成fibonacci序列。用for遍歷時會逐個列印生成的fibonacci數,max是生成的fibonacci序列中數字大小的上限。

在類的實現中,定義了乙個__iter__(self)方法,這個方法是在遍歷時被iter()呼叫,返回乙個迭代器。因為在遍歷的時候,是直接呼叫的python內建函式iter(),由iter()通過呼叫__iter__(self)獲得物件的迭代器。有了迭代器,就可以逐個遍歷元素了。而逐個遍歷的時候,也是使用內建的next()函式通過呼叫物件的__next__(self)方法對迭代器物件進行遍歷。所以要實現__iter__(self)__next__(self)。而且因為實現了__next__(self),所以在實現__iter__(self)的時候,直接返回self就可以。

為了更好理解,我再簡單重複下上面說的那一段:在迴圈遍歷自定義容器物件時,會使用python內建函式iter()呼叫遍歷物件的__iter__(self)獲得乙個迭代器,之後再迴圈對這個迭代器使用next()呼叫迭代器物件的__next__(self)__iter__只會被呼叫一次,而__next__會被呼叫 n 次。

下面說生成器。

生成器(generator)是建立迭代器的簡單而強大的工具。它們寫起來就像是正規的函式,只是在需要返回資料的時候使用yield語句。每次next()被呼叫時,生成器會返回它脫離的位置(它記憶語句最後一次執行的位置和所有的資料值)。以下示例演示了生成器可以很簡單的建立出來:

>>> def reverse(data):

... for index in range(len(data)-1, -1, -1):

... yield data[index]

...

>>> for char in reverse('hello'):

... print(char)

... ol

leh

關於迭代器和生成器的區別,生成器能做到迭代器能做的所有事,而且因為自動建立了__iter__()next()方法,生成器顯得特別簡潔,而且生成器也是高效的。除了建立和儲存程式狀態的自動方法,當發生器終結時,還會自動丟擲stopiteration異常。乙個帶有yield的函式就是乙個 生成器,它和普通函式不同,生成乙個 generator 看起來像函式呼叫,但不會執行任何函式**,直到對其呼叫next()(在 for 迴圈中會自動呼叫next())才開始執行。雖然執行流程仍按函式的流程執行,但每執行到乙個yield語句就會中斷,並返回乙個迭代值,下次執行時從yield的下乙個語句繼續執行。看起來就好像乙個函式在正常執行的過程中被yield中斷了數次,每次中斷都會通過yield返回當前的迭代值(yield暫停乙個函式,next()從其暫停處恢復其執行)。

另外對於生成器,python還提供了乙個生成器表示式:類似與乙個yield值的匿名函式。表示式本身看起來像列表推到, 但不是用方括號而是用圓括號包圍起來:

>>> unique_characters = 

>>> gen = (ord(c) for c in unique_characters)

>>> gen

at 0x7f2be4668678>

>>> for i in gen:

... print(i)

...

6979

8377

8278

8968

>>>

如果需要,可以將生成器表示式傳給tuplelist或是set來迭代所有的值並且返回元組、列表或是集合。在這種情況下,不需要一對額外的括號 ———— 直接將生成器表示式ord(c) for c in unique_characters傳給tuple()等函式就可以了, python 會推斷出它是乙個生成器表示式。

最後,為什麼要使用生成器?因為效率。使用生成器表示式取代列表解析可以同時節省 cpu 和 記憶體(ram)。如果你構造乙個列表的目的僅僅是傳遞給別的函式,(比如 傳遞給tuple()或者set()), 那就用生成器表示式替代吧!

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 ...

python 迭代器和生成器

迭代器是訪問集合元素的一種方式。迭代器物件從集合的第乙個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會後退,不過這也沒什麼,因為人們很少在迭代途中往後退。另外,迭代器的一大優點是不要求事先準備好整個迭代過程中所有的元素。迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之後,元素可...