自學Python:列表生成式、生成器、迭代器

列表生成式

列表生成式是python內置的一個用來創建列表的生成式,非常的強大和靈活!
比如說我們要生成一個包含1-10十個數字的列表,我們可以直接使用list(range(11))來生成:
在這裏插入圖片描述
但是我們如果要生成[1 * 1, 2 * 2, 3 * 3, 4 * 4, …, 10 * 10]這樣一個列表呢,第一種方法時使用循環:

但是這樣的話還是看起來非常的複雜,不太符合python簡單的特性,因此,我們可以使用列表生成式來完成這一操作,只使用一行代碼完成我們的要求:
在這裏插入圖片描述
由這行代碼可以看出,列表生成式的格式是這樣的,所有語句都包含在一對中括號中,最前面的是我們需要生成的元素,後面跟for循環就可以將一個列表創建出來,for循環後面還可以跟上if判斷語句,比如我們要生成一個包含1-10中的偶數平方值的列表,可以這樣做:
在這裏插入圖片描述
列表生成式中也可以有嵌套for循環,生成一個全排列:
在這裏插入圖片描述
我們來生成一個列表,包含當前目錄下所有目錄與文件:
在這裏插入圖片描述
列表生成式中的for循環其實也可以使用兩個甚至是多個變量,比如我們要從字典中取值的話,可以同時迭代key和value:
在這裏插入圖片描述
最後一個,我們使用列表生成式將一個列表中的元素全部變成小寫:
在這裏插入圖片描述
運用列表生成式,可以快速生成一個列表,可以通過一個列表推導出另一個列表,因此列表生成式也稱爲列表推導式。

生成器

通過列表生成式生成的列表,受到內存的限制,其容量肯定是有限的,而且,創建一個包含幾十一百萬元素的列表,不僅要佔用很大的內存空間,如果我們僅僅需要訪問前面的幾個元素,那後面的元素佔用的空間將會被白白浪費,所以,如果列表元素可以按照某種算法推算出來,我們就可以在循環的過程中不斷推算出後續的元素,這樣的話就不必創建完整的列表,從而節省大量的空間。在python中,這種一邊循環一邊計算的機制,稱爲生成器:generator

創建生成器的方法有很多種,其中最簡單的方法就是將列表生成式的[]改爲(),我們使用列表生成式的時候,可以直接打印出一個列表,但是我們怎麼打印出一個生成器中的元素呢?上面我們說過,生成器是一種邊循環邊計算的機制,它返回的並不會直接是一個列表,而是一個生成器,這個生成器包含了一種算法,生成一個個元素的算法,我們可以使用next()函數,不斷地獲取生成器的下一個返回值:
在這裏插入圖片描述
當使用next()函數獲得生成器的最後一個值之後,再次調用就會報錯,提示終止迭代:
在這裏插入圖片描述
這種不斷調用next()函數獲取生成器中的值的效率實在是太低了,正確的方法是使用for循環,因爲生成器也是一個可迭代對象:
在這裏插入圖片描述
我們在得到一個生成器後,基本不會使用next()函數去獲取生成器中的值,而是使用for循環,並且不用關心stopIteration的錯誤
生成器非常的強大,如果其包含的推算的算法非常複雜,使用類似於列表生成式的for循環無法實現的話,我們還可以使用函數來實現,這是創建生成器的第二種方法,比如說著名的斐波那契數列,從第三個數開始,每個數字的值都是其前兩個數字的和,斐波那契數列使用列表生成式寫不出來,因此我們可以使用函數來實現:
在這裏插入圖片描述
可以看到,fibs函數實際上是定義了斐波那契數列的推算規則,可以從第一個元素開始,推算出後續任意的元素,這種邏輯其實非常類似生成器。也就是說,上面推算斐波那契的函數和生成器僅一步之遙,要把fibs函數編程生成器,只需要把print(b)改爲yield b就可以了:
在這裏插入圖片描述
生成器的執行流程和函數的不一樣,函數是順序執行,遇到return語句或者最後一行函數語句就返回,但是生成器的話,在每次調用next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。
舉個例子:定義一個生成器,依次返回數字1, 3, 5:
在這裏插入圖片描述
調用該函數時,首先要返回一個生成器對象,然後用next()函數不斷獲取下一個返回值:
在這裏插入圖片描述
可以看到,odd()就是一個生成器,在執行過程中,遇到yield就中斷,再次調用next()就從上次中斷的地方繼續執行,第三次後沒有yield可執行,所以在第四次調用的時候就報錯。
小結:
生成器是非常強大的工具,在python中,可以簡單的把列表生成式改成generator,也可以通過函數實現複雜邏輯的generator。要理解生成器的工作原理,他是在for循環的過程中不斷計算出下一個元素,並在適當的條件結束for循環。對於函數改成的生成器來說,遇到return語句或者執行到函數體最後一行語句,就是結束生成器的指令,for循環隨之結束。

迭代器

我麼已經知道,可以直接作用於for循環的數據類型有以下幾種:
一類是集合數據類型,如list、tuple、dict、set、str等;
一類是generator,包括生成器和帶yield的generator function。
這些可以直接作用於for循環的對象統稱爲可迭代對象:Iterable。
可以使用isinstance()判斷一個對象是否是Iterable對象:
在這裏插入圖片描述
生成器不但可以作用於for循環,還可以被next()函數不斷調用並返回下一個值,直到最後拋出stopIteration錯誤表示無法繼續返回下一個值了。
可以被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator。
可以使用isinstance()判斷一個對象是否是Iterator對象:
在這裏插入圖片描述
生成器都是可迭代對象,但list、dict、str雖然是Iterable,卻不是Iterator。
把list、dict、str等Iterable變成Iterator可以使用iter()函數:
在這裏插入圖片描述
你可能會問,爲什麼list、dict、str等數據類型不是Iterator?
這是因爲Python的Iterator對象表示的是一個數據流,Iterator對象可以被next()函數調用並不斷返回下一個數據,直到沒有數據時拋出stopIteration錯誤,可以把這個數據流看作是一個有序序列,但我們不能提前知道序列的長度,只能不斷通過next(0函數實現按需計算下一個數據,所以Iterator的計算是惰性的,只有在需要時返回下一個數據時他纔會計算。
Iterator甚至可以表示一個無限大的數據流,例如全體自然數,而使用list是永遠也不可能存儲全體自然數的。
小結:
凡是可作用於for循環的對象都是Iterable類型;
凡是可作用於next(0函數的對象都是Iterator類型,他們表示一個惰性計算的序列;
集合數據類型如list、dict、str等是Iterable但不是Iterator,不過可以通過iter()函數獲得下一個Iterator對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章