決戰Python之巔(十三)生成器和迭代器

2021-09-03 07:10:37 字數 3239 閱讀 2789

拖了這麼久才來補生成器和迭代器- -

之前在講列表的時候並沒有經過這個東西,現在我來介紹一下。

列表生成式可以用一句話就能生成乙個列表,如a = [x for x in range(10)],這樣就能直接生成乙個0~9的列表。相對於利用for迴圈、while迴圈來說,更簡單快捷。當然你也可以這樣做b = [x**2 for x in range(10)],注意前面公式最多支援三元運算。

現在,我有乙個需求,即生成乙個有100000000(1億)個元素的列表,如果像上面一樣:d = [x for x in range(100000000)],一般的電腦請不要輕易嘗試,這種放縱的滋味會讓你的電腦宕機。壕隨意- -。但是即使配置好也發現需要等待一段時間才能給出結果,即使你不用列表生成式,用迴圈做也一樣。這是因為列表生成式總會把元素全都建立好才會返回,如果資料大一點,那將會占用很多記憶體,但我們實際使用的可能只有裡面的一小部分,這樣便做了很多無用功。

那麼,怎麼應對這種情況呢?有這麼乙個東西,可以將列表元素按照你規定的演算法算出,但只有你需要的時候才會生成,你用多少調多少,豈不快哉?

這就是生成器,官方解釋如下:

如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的過程中不斷推算出後續的元素呢?

這樣就不必建立完整的list,從而節省大量的空間。

在python中,這種一邊迴圈一邊計算的機制,稱為生成器:generator。-------沃.鎡基碩得

那怎麼建立呢?

與列表生成式類似,a = (x for x in range(10)),區別僅僅在於中括號變成了小括號。

這樣,你就有了乙個生成器。那怎麼用這個生成器呢?這裡我們要用到乙個next()語法,字面意思就是下乙個,我們來試下效果:

每呼叫一次next(a),便返回乙個元素。注意這裡只能不斷向前進,不能後退,即當next(a)返回3的時候,你不可能在next(a)返回2出來,前面的過了就過了,不能再回去了。

當你next返回最後乙個元素後,再次next,會有什麼效果?

這裡會丟擲乙個stopiteration的異常,告訴你生成器已經到頭了,再接下去就沒有了。(這個當我們後面學了捕捉異常之後另有用處)。

當然,一次次呼叫next(a)不太現實,這裡我們可以結合迴圈來做:

你會發現,當使用for迴圈的時候,就算到了盡頭,也不會報錯,即不需要關心stopiteration的錯誤。

有其一必有其二。如果推算的演算法比較複雜,用類似列表生成式的for迴圈無法實現的時候,還可以用函式來實現。

我們用斐波拉契函式做示範:

def fib(max):

n, a, b = 0, 0, 1

while n < max:

print(b)

a, b = b, a + b

n = n + 1

return 'done'

def fib(max):

n, a, b = 0, 0, 1

while n < max:

yield b

a, b = b, a + b

n = n + 1

# return 'done'

這就是定義generator的另一種方法。如果乙個函式定義中包含yield關鍵字,那麼這個函式就不再是乙個普通函式,而是乙個generator:

生成器與函式的執行流程不太一樣:

在每次呼叫next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。

我們已經知道,可以直接作用於for迴圈的資料型別有以下幾種:

一類是集合資料型別,如list、tuple、dict、set、str等;

一類是generator,包括生成器和帶yield的generator function。

這些可以直接作用於for迴圈的物件統稱為可迭代物件:iterable。可以使用==isinstance()==判斷乙個物件是否是iterable物件:

而生成器不但可以作用於for迴圈,還可以被next()函式不斷呼叫並返回下乙個值,直到最後丟擲stopiteration錯誤表示無法繼續返回下乙個值了。

可以被next()函式呼叫並不斷返回下乙個值的物件稱為迭代器:iterator。

可以使用isinstance()判斷乙個物件是否是iterator物件:

生成器都是iterator物件,但list、dict、str雖然是iterable,卻不是iterator。

把list、dict、str等iterable變成iterator可以使用iter()函式:

你可能會問,為什麼list、dict、str等資料型別不是iterator?

這是因為python的iterator物件表示的是乙個資料流,iterator物件可以被next()函式呼叫並不斷返回下乙個資料,直到沒有資料時丟擲stopiteration錯誤。可以把這個資料流看做是乙個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()函式實現按需計算下乙個資料,所以iterator的計算是惰性的,只有在需要返回下乙個資料時它才會計算。

iterator甚至可以表示乙個無限大的資料流,例如全體自然數。而使用list是永遠不可能儲存全體自然數的。

Python小白學習之路(二十三) 生成器補充

接著下雞蛋和吃包子!總是把生成器比喻成母雞下雞蛋,需要乙個下乙個,首先是下出來的雞蛋不能塞回 母雞肚子裡,其次是乙個母雞一生只能下一定數量的雞蛋,下完了就死掉了 通過程式來理解什麼意思 程式一 deftest for i in range 2 yield it test for i in t pri...

決戰Python之巔(四)

先總體回顧一下第一章的內容 1.三大類程式語言 機器語言 組合語言 高階語言 其中高階語言又分為解釋型 編譯型。2.python的使用者互動 輸入 input 輸出 print。3.注釋 單行使用 多行使用三對單引號 即 4.變數的規範 1.變數名只能是字母 數字或下劃線的任意組合 2.變數名的第乙...

決戰Python之巔(十一)

本篇將介紹遞迴以及函式的內建方法。之前我們已經講過,函式內部可以呼叫其他函式。如果乙個函式在內部呼叫自身,這個函式就是遞迴函式 def func print 遞迴函式 func 這就是乙個遞迴函式,如果你執行這段 的話,理想中會列印無數行 遞迴函式。但事實上並不會 因為目前這個遞迴相當於乙個死迴圈,...