Python 學習之列表

ARM的程式設計師敲著詩歌的夢發表於2019-01-27


列表是可變的,即可修改其內容。

函式 list

如果你想使用字串來建立列表,那就用函式list( 它實際上是一個類,而不是函式,但眼下,這種差別並不重要。),例如:

In [1]: a = list("hello")

In [2]: a
Out[2]: ['h', 'e', 'l', 'l', 'o']

要將字元列表(如前述程式碼第 3 行的 a)轉換為字串,可使用下面的表示式:
''.join(a)

In [3]: ''.join(a)
Out[3]: 'hello'

基本的列表操作

可對列表執行所有的標準序列操作,如索引、切片、拼接和相乘,但列表的有趣之處在於它是可以修改的。本節將介紹一些修改列表的方式:給元素賦值、刪除元素、給切片賦值以及使用列表的方法。(請注意,並非所有列表方法都會修改列表。)

修改列表:給元素賦值

修改列表很容易,只需使用普通賦值語句即可——使用索引表示法給特定位置的元素賦值,如x[1] = 2

例如:

In [7]: x = [1,1,1]

In [8]: x[1] = 2

In [9]: x
Out[9]: [1, 2, 1]

注意:不能給不存在的元素賦值,因此如果列表的長度為2,你就不能寫 “x[2]=…”

刪除元素

從列表中刪除元素也很容易,只需使用del語句即可。

In [11]: names = ['Alice', 'Beth', 'Cecil', 'Dee-Dee', 'Earl'] 

In [12]: del names[2]

In [13]: names
Out[13]: ['Alice', 'Beth', 'Dee-Dee', 'Earl']

注意到 Cecil 徹底消失了,而列表的長度也從5變成了4。

給切片賦值

切片是一項極其強大的功能,而能夠給切片賦值讓這項功能顯得更加強大。

In [14]: name = list('Perl') 

In [15]: name
Out[15]: ['P', 'e', 'r', 'l']

In [16]: name[2:]=list('ar')

In [17]: name
Out[17]: ['P', 'e', 'a', 'r']

從上述程式碼可知,可同時給多個元素賦值。比較神奇的是,通過使用切片賦值,可將切片替換為長度與其不同的序列。

我們再看一個例子.

In [18]: name = list('Perl')

In [19]: name[1:]=list('ython')

In [20]: name
Out[20]: ['P', 'y', 't', 'h', 'o', 'n']

可以看到,把原本長度為3的切片換成了長度為5的切片。

使用切片賦值還可在不替換原有元素的情況下插入新元素。

In [21]: nums = [1,5]

In [22]: nums[1:1] = [2,3,4]

In [23]: nums
Out[23]: [1, 2, 3, 4, 5]

在這裡,我們“替換”了一個空切片,相當於插入了一個序列。如果你要在位置 x 處插入一個序列,那麼就可以用 somelist[x:x] = […]

你可採取相反的措施來刪除切片。

In [23]: nums
Out[23]: [1, 2, 3, 4, 5]

In [24]: nums[1:4] = []

In [25]: nums
Out[25]: [1, 5]

上述程式碼與del numbers[1:4]等效。

In [26]: nums = [1,2,3,4,5]

In [27]: del nums[1:4]

In [28]: nums
Out[28]: [1, 5]

可以理解為刪除切片 nums[1:4]

我們執行步長不為1(乃至為負)的切片賦值。

In [29]: nums = [1,2,3,4,5,6,7,8,9,10]

In [30]: nums[::2]=[0,0,0,0,0]

In [31]: nums
Out[31]: [0, 2, 0, 4, 0, 6, 0, 8, 0, 10]

In [31]: nums
Out[31]: [0, 2, 0, 4, 0, 6, 0, 8, 0, 10]

In [32]: nums[-1::-3]=[77,88,99]
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-32-be8451000971> in <module>()
----> 1 nums[-1::-3]=[77,88,99]

ValueError: attempt to assign sequence of size 3 to extended slice of size 4

為什麼會出錯呢?

因為 nums[-1::-3] 是一個長度為4的切片,而我們只提供了長度為3的序列 [77,88,99],這樣是不行的。我們修改一下:

In [33]: nums[-1::-3]=[77,88,99,66]

In [34]: nums
Out[34]: [66, 2, 0, 99, 0, 6, 88, 8, 0, 77]

列表方法

方法是與物件聯絡緊密的函式。通常,像下面這樣呼叫方法:
object.method(arguments)

方法呼叫與函式呼叫很像,只是在方法名前加上了物件和點號。列表包含多個可用來檢視或修改其內容的方法。

append

方法 append 用於將一個物件附加到列表末尾。

In [35]: lst = [1,2,3]

In [36]: lst.append(4)

In [37]: lst
Out[37]: [1, 2, 3, 4]

注意,如果你忘了方法名字也沒有關係,當輸入完lst.後,按tab鍵,就可以聯想出來所有的方法.

In [38]: lst.
lst.append   lst.copy     lst.extend   lst.insert   lst.remove   lst.sort     
lst.clear    lst.count    lst.index    lst.pop      lst.reverse  

你可能會問,為何給列表取lst這樣糟糕的名字,而不稱之為list呢?原因是 list 是一個內建函式( 實際上,從Python 2.2起,list就是型別,而不是函式了),如果將前述列表命名為list,就無法呼叫這個函式。

另外請注意,與其他幾個類似的方法一樣,append 就地修改列表。這意味著它不會返回修改後的新列表,而是直接修改舊列表。

clear

方法clear就地清空列表的內容。

In [40]: lst
Out[40]: [1, 2, 3]

In [41]: lst.clear()

In [42]: lst
Out[42]: []

這類似於切片賦值語句lst[:] = []

copy

方法 copy 複製列表。常規賦值只是將另一個名稱關聯到列表。

In [56]: a
Out[56]: [1, 2, 3]

In [57]: b = a

In [58]: b[1]=4

In [59]: a
Out[59]: [1, 4, 3]

In [60]: b
Out[60]: [1, 4, 3]

可以看到,當執行b = a的時候,其實是把 b 關聯到列表 a,也就是說 b 和 a 是同一個列表;

In [51]: a = [1,2,3]

In [52]: b = a.copy()

In [53]: b[1]=4

In [54]: a
Out[54]: [1, 2, 3]

In [55]: b
Out[55]: [1, 4, 3]

可以看到,b 是獨立於 a 的一個列表,修改 b 並不會修改 a;

所以,要讓a和b指向不同的列表,就必須將b關聯到a的副本(a.copy())。 這類似於使用list(a)或者a[:],他們也都複製 a

In [61]: a = [1,2,3]

In [62]: c = a[:]

In [63]: b = list(a)

In [64]: c[0] = 5

In [65]: b[0] = 7

In [66]: a
Out[66]: [1, 2, 3]

In [67]: b
Out[67]: [7, 2, 3]

In [68]: c
Out[68]: [5, 2, 3]

count

方法count計算指定的元素在列表中出現了多少次。

In [69]: lst = [1,2,3,3,4,5,3]

In [70]: lst.count(3)
Out[70]: 3

In [71]: lst.count(8)
Out[71]: 0

extend

方法extend讓你能夠同時將多個值附加到列表末尾,為此可將這些值組成的序列作為引數提供給方法extend。換言之,你可使用一個列表來擴充套件另一個列表。

In [72]: a = [1,2,3]

In [73]: b = [4,5,6]

In [74]: a.extend(b)

In [75]: a
Out[75]: [1, 2, 3, 4, 5, 6]

In [76]: b
Out[76]: [4, 5, 6]

這看起來類似於拼接,但存在一個重要差別,那就是將修改被擴充套件的序列(這裡是a)。在常規拼接中,情況是返回一個全新的序列,並不會修改原來的序列。

In [77]: a = [1,2,3]

In [78]: b = [4,5,6]

In [79]: a + b
Out[79]: [1, 2, 3, 4, 5, 6]

In [80]: a
Out[80]: [1, 2, 3]

In [81]: b
Out[81]: [4, 5, 6]

如你所見,拼接出來的列表(第6行)與前一個示例擴充套件得到的列表(第8行)完全相同,但在這裡a並沒有被修
改。鑑於常規拼接必須使用a和b的副本建立一個新列表,因此如果你要獲得exten的效果,可以這樣寫:

In [82]: a = a + b

In [83]: a
Out[83]: [1, 2, 3, 4, 5, 6]

雖然效果一樣,但是效率低於 extend。

另外,拼接操作並非就地執行的,即它不會修改原來的列表。要獲得與extend相同的效果,也可將列表賦給切片,如下所示:

In [84]: a = [1,2,3]

In [85]: b = [4,5,6]

In [86]: a[len(a):] = b

In [87]: a
Out[87]: [1, 2, 3, 4, 5, 6]

這雖然可行,但可讀性不好。

index

方法index在列表中查詢指定值第一次出現的索引。

In [89]: lst = [1,2,3,4,5,1,2]

In [90]: lst.index(1)
Out[90]: 0

In [91]: lst.index(6)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-91-1fe7e2916666> in <module>()
----> 1 lst.index(6)

ValueError: 6 is not in list

然而,搜尋 6 時引發了異常,因為根本就沒有找到這個數。

insert

方法insert用於將一個物件插入列表。

In [92]: nums = [1,2,3,5,6]

In [93]: nums.insert(3,'four')

In [94]: nums
Out[94]: [1, 2, 3, 'four', 5, 6]

引數中的3指定了要插入的索引位置。

也可使用給空切片賦值來獲得與insert一樣的效果。

In [98]: nums = [1,2,3,5,6]

In [99]: nums[3:3] = ['four']

In [100]: nums
Out[100]: [1, 2, 3, 'four', 5, 6]

這雖巧妙,但可讀性根本無法與使用insert媲美。

注意,第3行不能寫成nums[3:3] = 'four'

否則就成了:

In [95]: nums = [1,2,3,5,6]

In [96]: nums[3:3] = 'four'

In [97]: nums
Out[97]: [1, 2, 3, 'f', 'o', 'u', 'r', 5, 6]

pop

方法pop從列表中刪除一個元素,並返回這一元素。

如果不指定引數,那麼就刪除最後一個元素;如果在引數中指定索引,那麼就刪除索引對應的元素。

In [101]: x = [1,2,3,4,5,6]

In [102]: x.pop()
Out[102]: 6

In [103]: x.pop()
Out[103]: 5

In [104]: x
Out[104]: [1, 2, 3, 4]

In [105]: x.pop(1)
Out[105]: 2

In [106]: x
Out[106]: [1, 3, 4]

注意:pop是唯一既修改列表又返回一個非None值的列表方法。

使用pop可實現一種常見的資料結構——棧(stack)。

push和pop是兩種最基本的棧操作。Python沒有提供push,但可使用append來替代。

remove

方法remove用於刪除第一個為指定值的元素。

In [4]: x = [1,2,3,1,4,5]

In [5]: x.remove(1)

In [6]: x
Out[6]: [2, 3, 1, 4, 5]

請注意,remove是就地修改且不返回值的方法之一。不同於pop的是,它修改列表,但不返回任何值。

reverse

方法reverse按相反的順序排列列表中的元素。

In [7]: x = [1,2,3,4,5]

In [8]: x.reverse()

In [9]: x
Out[9]: [5, 4, 3, 2, 1]

注意到reverse修改列表,但不返回任何值。

sort

方法sort用於對列表就地排序 。就地排序意味著對原來的列表進行修改,使其元素按順序排列,而不是返回排序後的列表的副本。

In [10]: x = [2,3,9,1,4,5,5]

In [11]: x.sort()

In [12]: x
Out[12]: [1, 2, 3, 4, 5, 5, 9]

前面介紹了多個修改列表而不返回任何值的方法,在大多數情況下,這種行為都相當自然(例如,對append來說就如此)。需要強調sort的行為也是這樣的,但是這種行為給很多人都帶來了困惑。在需要排序後的列表副本並保留原始列表不變時,通常會遭遇這種困惑。為實現這種目標,一種直觀(但錯誤)的方式是像下面這樣做:

In [19]: x = [3,5,2,1,8]

In [20]: y = x.sort()

In [21]: print(y)
None

鑑於sort修改x且不返回任何值,最終的結果是x是經過排序的,而y包含None。為實現前述目標,正確的方式之一是先將y關聯到x的副本,再對y進行排序,如下所示:

In [22]: x = [3,5,2,1,8]

In [23]: y = x.copy()

In [24]: y.sort()

In [25]: y
Out[25]: [1, 2, 3, 5, 8]

In [26]: x
Out[26]: [3, 5, 2, 1, 8]

為獲取排序後的列表的副本,另一種方式是使用函式sorted。

In [27]: x = [3,5,2,1,8]

In [28]: y = sorted(x)

In [29]: y
Out[29]: [1, 2, 3, 5, 8]

In [30]: x
Out[30]: [3, 5, 2, 1, 8]

實際上,sorted 這個函式可用於任何序列,但總是返回一個列表 。

In [31]: sorted('BACW')
Out[31]: ['A', 'B', 'C', 'W']

參考資料

《Python基礎教程(第三版)》,人民郵電出版社

相關文章