切片
(1)對這種經常取指定索引範圍的操作,用循環十分繁瑣,是以,python提供了切片(slice)操作符,能大大簡化這種操作。
對應上面的問題,取前3個元素,用一行代碼就可以完成切片:
<code> l[0:3]</code>表示,從索引<code>0</code>開始取,直到索引<code>3</code>為止,但不包括索引<code>3</code>。即索引<code>0</code>,<code>1</code>,<code>2</code>,正好是3個元素。
(2)如果第一個索引是<code>0</code>,還可以省略:
(3)類似的,既然python支援<code>l[-1]</code>取倒數第一個元素,那麼它同樣支援倒數切片,試試:
(4)前10個數,每兩個取一個:
(5)所有數,每5個取一個:
(6)甚至什麼都不寫,隻寫<code>[:]</code>就可以原樣複制一個list:
(7)tuple也是一種list,唯一差別是tuple不可變。是以,tuple也可以用切片操作,隻是操作的結果仍是tuple:
(8)字元串<code>'xxx'</code>也可以看成是一種list,每個元素就是一個字元。是以,字元串也可以用切片操作,隻是操作結果仍是字元串:
2.疊代
(1)如果給定一個list或tuple,我們可以通過<code>for</code>循環來周遊這個list或tuple,這種周遊我們稱為疊代(iteration)。
(2)預設情況下,dict疊代的是key。如果要疊代value,可以用<code>for value in d.values()</code>,如果要同時疊代key和value,可以用<code>for k, v in d.items()</code>。
(3)由于字元串也是可疊代對象,是以,也可以作用于<code>for</code>循環:
(4)那麼,如何判斷一個對象是可疊代對象呢?方法是通過collections子產品的iterable類型判斷:
(5)如果要對list實作類似java那樣的下标循環怎麼辦?python内置的<code>enumerate</code>函數可以把一個list變成索引-元素對,這樣就可以在<code>for</code>循環中同時疊代索引和元素本身:
(6)任何可疊代對象都可以作用于<code>for</code>循環,包括我們自定義的資料類型,隻要符合疊代條件,就可以使用<code>for</code>循環。
3.清單生成式
(1)清單生成式即list comprehensions,是python内置的非常簡單卻強大的可以用來建立list的生成式。
(2)要生成<code>[1x1, 2x2, 3x3, ..., 10x10]</code>怎麼做?方法一是循環.
清單生成式則可以用一行語句代替循環生成上面的list:
(3)for循環後面還可以加上if判斷,這樣我們就可以篩選出僅偶數的平方:
(4)還可以使用兩層循環,可以生成全排列:
(5)運用清單生成式,可以寫出非常簡潔的代碼。例如,列出目前目錄下的所有檔案和目錄名,可以通過一行代碼實作:
<code>(6)for</code>循環其實可以同時使用兩個甚至多個變量,比如<code>dict</code>的<code>items()</code>可以同時疊代key和value:
是以,清單生成式也可以使用兩個變量來生成list:
(7)最後把一個list中所有的字元串變成小寫:
(8)如果list中既包含字元串,又包含整數,由于非字元串類型沒有<code>lower()</code>方法,是以清單生成式會報錯:
使用内建的<code>isinstance</code>函數可以判斷一個變量是不是字元串
結果如下:
4.生成器
(1)如果清單元素可以按照某種算法推算出來,那我們是否可以在循環的過程中不斷推算出後續的元素呢?這樣就不必建立完整的list,進而節省大量的空間。在python中,這種一邊循環一邊計算的機制,稱為生成器:generator。
(2)要建立一個generator,有很多種方法。第一種方法很簡單,隻要把一個清單生成式的<code>[]</code>改成<code>()</code>,就建立了一個generator:
(3)怎麼列印出generator的每一個元素呢?
如果要一個一個列印出來,可以通過<code>next()</code>函數獲得generator的下一個傳回值:
計算到最後一個元素,沒有更多的元素時,抛出<code>stopiteration</code>的錯誤。
(4)
正确的方法是使用<code>for</code>循環,因為generator也是可疊代對象:
(5)
如果推算的算法比較複雜,用類似清單生成式的<code>for</code>循環無法實作的時候,還可以用函數來實作。
比如,著名的斐波拉契數列(fibonacci),除第一個和第二個數外,任意一個數都可由前兩個數相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
斐波拉契數列用清單生成式寫不出來,但是,用函數把它列印出來卻很容易:
注意,指派語句:
相當于:
但不必顯式寫出臨時變量t就可以指派。
上面的函數可以輸出斐波那契數列的前n個數:
仔細觀察,可以看出,<code>fib</code>函數實際上是定義了斐波拉契數列的推算規則,可以從第一個元素開始,推算出後續任意的元素,這種邏輯其實非常類似generator。
也就是說,上面的函數和generator僅一步之遙。要把<code>fib</code>函數變成generator,隻需要把<code>print(b)</code>改為<code>yield b</code>就可以了:
這就是定義generator的另一種方法。如果一個函數定義中包含<code>yield</code>關鍵字,那麼這個函數就不再是一個普通函數,而是一個generator:
(6)函數是順序執行,遇到<code>return</code>語句或者最後一行函數語句就傳回。而變成generator的函數,在每次調用<code>next()</code>的時候執行,遇到<code>yield</code>語句傳回,再次執行時從上次傳回的<code>yield</code>語句處繼續執行。
(7)但是用<code>for</code>循環調用generator時,發現拿不到generator的<code>return</code>語句的傳回值。如果想要拿到傳回值,必須捕獲<code>stopiteration</code>錯誤,傳回值包含在<code>stopiteration</code>的<code>value</code>中:
(8)執行個體
楊輝三角定義如下:
把每一行看做一個list,試寫一個generator,不斷輸出下一行的list:
别人的triangles()函數代碼如下:
(9)請注意區分普通函數和generator函數,普通函數調用直接傳回結果:
generator函數的“調用”實際傳回一個generator對象:
5.疊代器
(1)我們已經知道,可以直接作用于<code>for</code>循環的資料類型有以下幾種:
一類是集合資料類型,如<code>list</code>、<code>tuple</code>、<code>dict</code>、<code>set</code>、<code>str</code>等;
一類是<code>generator</code>,包括生成器和帶<code>yield</code>的generator function。
這些可以直接作用于<code>for</code>循環的對象統稱為可疊代對象:<code>iterable</code>。
(2)可以使用<code>isinstance()</code>判斷一個對象是否是<code>iterable</code>對象:
(3)可以被<code>next()</code>函數調用并不斷傳回下一個值的對象稱為疊代器:<code>iterator</code>。
可以使用<code>isinstance()</code>判斷一個對象是否是<code>iterator</code>對象:
生成器都是<code>iterator</code>對象,但<code>list</code>、<code>dict</code>、<code>str</code>雖然是<code>iterable</code>,卻不是<code>iterator</code>。
把<code>list</code>、<code>dict</code>、<code>str</code>等<code>iterable</code>變成<code>iterator</code>可以使用<code>iter()</code>函數:
為什麼<code>list</code>、<code>dict</code>、<code>str</code>等資料類型不是<code>iterator</code>?
這是因為python的<code>iterator</code>對象表示的是一個資料流,iterator對象可以被<code>next()</code>函數調用并不斷傳回下一個資料,直到沒有資料時抛出<code>stopiteration</code>錯誤。可以把這個資料流看做是一個有序序列,但我們卻不能提前知道序列的長度,隻能不斷通過<code>next()</code>函數實作按需計算下一個資料,是以<code>iterator</code>的計算是惰性的,隻有在需要傳回下一個資料時它才會計算。
<code>iterator</code>甚至可以表示一個無限大的資料流,例如全體自然數。而使用list是永遠不可能存儲全體自然數的。