迭代器 VS 生成器:Python告訴你!

最近有讀者留言,問小編生成器與迭代器有什麼區別,小編坦言玩了將近兩年的python,還真沒有直接用過生成器和迭代器的相關方法和協議,我也是惡補了兩天,將我瞭解到的生成器和迭代器致使給大家講一講:

先說說迭代器(iterator),迭代器是訪問可迭代對象的工具,是指用iter(obj)函數返回的對象(實例),並用next(it)函數獲取可迭代對象的數據。關於迭代器函數iter,其語法為:it=iter(iterable)從可迭代對象中返回一個迭代器,iterable必須是可迭代對象,而python數據類型都可以作為可迭代對象使用,此外range函數也是可迭代對象,而next(it)方法是指從迭代器iterator中獲取下一個記錄,如果無法獲取下一條記錄,則觸發StopIterator錯誤,下面就是一個簡單的迭代器函數iter示例:

迭代器 VS 生成器:Python告訴你!

迭代器函數

可以發現,迭代器只能向前取值,不能後退,next方法使用一次,就代表指針向前進一,如果迭代器無法獲取下一條記錄,則會觸發StopIterator錯誤,於是小編有個不成熟的想法,python的for循環是不是可以用迭代器+while模擬一下,因為for循環對象也是可迭代對象,但與迭代器不同的是,for循環越界時並不會報錯,下面是相關代碼:

迭代器 VS 生成器:Python告訴你!

迭代器+while模擬for循環

因此for語句的本質可能就是while循環+迭代器,for語句裡先從可迭代對象中返回一個迭代器,對迭代器執行next方法,如果觸發StopIterator異常,迭代器則生成完畢,而代碼中的print輸出,在for循環裡可以通過else語句體現,打印print("循環結束")。

下面解釋一下什麼是生成器,生成器是能夠動態提供數據的對象,生成器對象也是可迭代對象(實例),生成器主要有兩種,一種是生成器函數,一種是生成器表達式。那什麼是生成器函數呢?含有yield語句的函數就是生成器函數,此函數被調用將返回一個生成器對象,可以迭代器調用,可以直接使用next()方法,也可以for循環使用,代碼如下:

迭代器 VS 生成器:Python告訴你!

生成器函數

可以看出,生成器對象是一個可迭代對象,可以通過迭代器調用,也可以for循環使用,下面再舉一個生成器例子,寫一個生成器函數myeven(start, stop) ,此函數用來被生成從start開始到stop結束(不包含)區間內的一系列偶數,代碼如下:

迭代器 VS 生成器:Python告訴你!

生成器示例-生成偶數

相信大家還記得range()函數吧,作為一個可迭代對象,可以和for循環配合生成隨機數,而range()函數的本質可以模擬成一個生成器對象。前面已經說過,語法for i in range(num)輸出i相當於迭代器的next函數,一直往前執行,找range()函數要i,執行到yield語句時,生成一個i,立即返回給i,這時繼續找range()函數要i,繼續執行i+=1,說白了,range()函數沒有結束,而是兩個循環一前一後相互執行,稱之為協程,而當yield不能再提供i時,會觸發一個StopIteration異常,結束執行!

那解釋一下生成器的另外一種形式:生成器表達式。生成器對象 = ( 表達式 for 變量 in 可迭代對象 if 真值表達式) ,其中,if子句可以省略,相當於用推導式的形式創建一個新的生成器,生成器表達式和生成器函數一樣,都是生成一個生成器對象,而括號只是一個生成器工具,是指有需要生成元素時,將for循環每生成的一個元素作為x傳遞給next(it),具體看代碼:

迭代器 VS 生成器:Python告訴你!

生成器表達式

生成器的最大好處就在於用多少,生成多少,既保留了當前狀態,下次又可在另外一個地方調用它,它會繼續按以前狀態繼續執行下去,這對於數據量很大的程序有很大的用處。接著我們來看一個高級一點的,這裡我們以產生斐波那契數列的前40個數為例,一般的方法都會產生大量的重複計算,生成的大量數據會佔滿內存,但是我們的生成器就可以完美解決這個問題。我們可以產生一個生成器,需要多少取多少即可,直接上代碼:

迭代器 VS 生成器:Python告訴你!

斐波那契數列

受制於水平的有限,這裡將迭代器和生成器進行了簡單的對比,而生成器的主要優勢在於隨用隨時生成,不佔用內存,尤其是在生成一個無窮數列的時候作用明顯,不過小編想說,無論是用生成器生成數據,還是用遞歸或是其他方法,代碼邏輯才是最重要的。需要交流和切磋的讀者朋友,請在評論區積極留言,歡迎關注頭條號:杜哥說python。


分享到:


相關文章: