天天看點

Python基礎筆記5

切片

(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是永遠不可能存儲全體自然數的。