標籤:
一 前言
學習進階特性的時候也許會感覺到有些許的難,這些新的特性在以前c/c++中是沒有遇到過的,而且c/c++也不支援這樣簡便但又強大的文法。
二 切片
談到切片,可以想像到切蘿蔔,拿到蘿蔔的某一段,用這個來比喻這裡的切片非常貼切。python中的切片操作就是取list或者tuple中的某一段。
比如,有以下定義的list:
#define a listl=[‘Luffy‘,‘Corey‘,‘Nancy‘,‘Jeffrey‘,‘Kyle‘,‘Avery‘,‘Jason‘,‘Sunny‘]
取其前3個元素的方法有兩種,代碼如下:
>>> l[:3][‘Luffy‘, ‘Corey‘, ‘Nancy‘]>>> l[0:3][‘Luffy‘, ‘Corey‘, ‘Nancy‘]
也就是說,從0開始的話可以省略。
取第2個到第4個元素的代碼如下:
>>> l[1:5][‘Corey‘, ‘Nancy‘, ‘Jeffrey‘, ‘Kyle‘]
取倒數第2個直到最後一個的代碼如下:
>>> l[-2:][‘Jason‘, ‘Sunny‘]
在不知道list長度的情況下取整個list的內容,代碼如下:
>>> l[:][‘Luffy‘, ‘Corey‘, ‘Nancy‘, ‘Jeffrey‘, ‘Kyle‘, ‘Avery‘, ‘Jason‘, ‘Sunny‘]
在整個list中每2個取1個:
>>> l[::2][‘Luffy‘, ‘Nancy‘, ‘Kyle‘, ‘Jason‘]
在list中前6個中每2個取1個:
>>> l[:5:2][‘Luffy‘, ‘Nancy‘, ‘Kyle‘]
在實際的編輯代碼中,經常可以把這裡的切片操作中的指向list的變數替換成list本身,如下所示:
>>> [‘Luffy‘, ‘Corey‘, ‘Nancy‘, ‘Jeffrey‘, ‘Kyle‘, ‘Avery‘, ‘Jason‘, ‘Sunny‘][:3][‘Luffy‘, ‘Corey‘, ‘Nancy‘]
tuple和字串都可以看成是一個list,故上述文法也是可以對其使用的。
三 列表產生式
列表產生式(List Comprehensions)是python中內建的非常強大的用來建立list的產生式。
最簡單的例子,我們要建立一個從1到10的列表,可以用
list(range(1,11))
這樣簡簡單單的一行代碼搞定。但是要產生更複雜的列表該怎麼辦呢?
產生[1x1,2x2,3x3,...,10x10]這樣的列表該怎麼辦呢?使用迴圈當然是可以實現的,但是代碼過於複雜,使用列表產生式則只需要如下一行代碼:
>>> [x*x for x in range(1,11)][1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
如果再加上只計算偶數的平方,那也不複雜,只需要在for迴圈後面加上if判斷條件即可。
>>> [x*x for x in range(1,11) if x % 2 == 0][4, 16, 36, 64, 100]
還可以使用兩層迴圈,
>>> [x+y for x in ‘ABC‘ for y in ‘XYZ‘][‘AX‘, ‘AY‘, ‘AZ‘, ‘BX‘, ‘BY‘, ‘BZ‘, ‘CX‘, ‘CY‘, ‘CZ‘]
寫了這麼多的列表產生式,我想大家也都明白了這文法的由來。其實也就是將正常的文法反轉,將最裡層的計算放在最前面。如最後一個列表產生式可以寫成如下正常的文法:
for x in ‘ABC‘:for y in ‘XYZ‘:print(x+y)
四 產生器
有了列表產生式,我們可以直接建立一個列表,但是如果考慮到記憶體限制時,我們就不能建立元素個數很多的列表了,那此時我們該怎麼辦呢?
python提供一個叫做產生器的機制,通過產生器可以推算出後續的元素,這樣就不用一次建立出所有的元素。要建立一個產生器,有兩種方法:
第一種方法:把列表產生式的[]改成(),就建立了一個generator。
如下面代碼所示:
>>> g=(x for x in range(10))>>> print(next(g))0
要擷取產生器的第一個元素,可以直接對g調用next函數。當然,也可以使用for迴圈來遍曆整個產生器下一步產生的資料。
第二種方法:如果推算的方法過於複雜,列表產生式無法實現時,就可以通過函數來實現。相對於從列表產生式到Generator,從函數到Generator也很簡單,只需要先寫好函數,然後再在某個位置上加上yield關鍵字就可以了。
比如,產生一個Fibonacci數列的函數如下:
def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n = n + 1 return ‘done‘
要把這個函數轉換成generator,只需要把print(b)這行代碼替換成yield b就可以了。
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return ‘done‘
含有yield關鍵字的函數就不再是一個函數了,而是一個generator。要注意的是,generator的執行流程與函數不一樣,在遇到yield時返回,當下次再調用時再從上次返回的yield處繼續執行。
五 迭代器
可以直接作用於for迴圈的對象統稱為可迭代對象:Iterable,可以使用isinstance()判斷一個對象是否是Iterable對象。產生器不僅可以由for迴圈進行遍曆,還可以使用next()遍曆。我們把可以被next()函數調用並不斷返回下一個值的對象統稱為迭代器:Iterator。
這裡要區分一個Iterable和Iterator,list,dict,str都是Iterable,但不是Iterator(可以使用iter()函數把Iterable變成Iterator)。Iterator可以是一個無限大的資料流,不能提前知道整個序列的長度,這些都是Iterable不能達到的要求。
六 後記
這裡提到的都是我在python中才學習到的一些編程的新特性。如有錯誤之處,敬請留言!!!
[原創]Python入門學習之進階特性