初識生成器
說到生成器還是要從列表推導式說起,關於列表推導式可以看看《python3基礎之如何使用列表推導式》。先看一個簡單的列表推導式:
可以看到列表推導式是用中括號將式子括起來的,如果把中括號改成小括號,那它就變成一個生成器了:
按照推導式的理論,看這式子的結構我還以為list2是一個元組推導式呢。看來python裡應該沒有元組推導式了。現在已經知道生成器長什麼樣了,那生成器又有什麼用呢?寫個例子測試一下吧:
這麼看生成器和列表好像是一樣的,那要生成器幹什麼呢?實際上生成器像是保存了一套算法的一個對象,剛開始的時候並它沒有實際的值,只有在使用時才去生成。也就是說到第二for執行之前list2裡並沒有2和3這兩個值。而列表推導式會先計算出所有的元素,也就是說list1在第一個for執行之前已經存在2和3這兩個值了。為了驗證這點寫個例子測試一下:
為了看到效果,我們將列表推導式和生成器的range改為了200000.程序運行時看到list2直接列印出來了,而list1要經過十幾秒才列印出來(生成列表花費了十幾秒)。經過這麼比較生成器的優勢就體現出來了,對於列表內的元素數量較大的情況下,生成器可以減少內存。而對於列表中存在耗時操作的對象時,生成器又能提高運行效率(因為它生成一個就能先用一個)。
函數生成器
上面那種生成器是通過一個表達式來表示的,如果邏輯需要很複雜的話,用式子就不好表示了。這時候可以用函數的方式來創建生成器。函數創建生成器的形式又是怎樣的呢?舉個例子:
函數中包含yield (e後面是小寫的字母'L'),那麼函數返回的就是一個生成器對象。 生成器也是一種可迭代對象,yield的作用就是返回一次迭代的值。我們通過next獲取生成器的值:
從例子中可以看到我們首先創建了一個生成器,第一次調用next獲取了第一yield返回的值,第二次調用next獲取的是第二個yield返回的值。它並不是整個函數直接返回一個結果,而是在使用時才生成數據。yield返回結果後好像暫停了一樣,直到要獲取生成器的下一個值時,再從剛才的yield後面繼續運行。