Python序列(列表list和元組tuple)用法完全攻略

2020-07-16 10:04:45
所謂序列,指的是一種包含多項資料的資料結構,序列包含的多個資料項(也叫成員)按順序排列,可通過索引來存取成員。

Python 的常見序列型別包括字串、列表和元組。前一章介紹過的字串,其實就是一種常見的序列,通過索引存取字串內的字元程式就是序列的示範程式。

本節介紹的序列主要是指列表和元組,這兩種型別看起來非常相似,最主要的區別在於:元組是不可變的,元組一旦構建出來,程式就不能修改元組所包含的成員(就像字串也是不可變的,程式無法修改字串所包含的字元序列);但列表是可變的,程式可以修改列表所包含的元素。

在具體的程式設計過程中,如果只是固定地儲存多個資料項,則不需要修改它們,此時就應該使用元組;反之,就應該使用列表。此外,在某些時候,程式需要使用不可變的物件,比如 Python 要求字典的 key 必須是不可變的,此時程式就只能使用元組。

簡單講,列表和元組的關係就是可變和不可變的關係。

建立列表和元組

建立列表和元組的語法也有點相似,區別只是建立列表使用方括號,建立元組使用圓括號,並在括號中列出元組的元素,元素之間以英文逗號隔開。

建立列表的語法格式如下:

[ele1,ele2,ele3,...]

建立元組的語法格式如下:

(ele1,ele2,ele3,...)

下面程式碼示範了在程式中定義列表和元組:
a_tuple = ('crazyit', 20, 5.6, 'fkit', -17)
print(a_tuple)
# 存取第1個元素
print(a_tuple[0]) # crazyit
# 存取第2個元素
print(a_tuple[1]) # 20
# 存取倒數第1個元素
print(a_tuple[-1]) # -17
# 存取倒數第2個元素
print(a_tuple[-2]) # -fkit

列表和元組切片

與前面介紹的字串操作類似的是,列表和元組同樣也可使用索引獲取中間一段,這種用法被稱為 slice(分片或切片)。slice 的完整語法格式如下:

[start : end : step]

上面語法中 start、end 兩個索引值都可使用正數或負數,其中負數表示從倒數開始。該語法表示從 start 索引的元素開始(包含),到 end 索引的元素結束(不包含)的所有元素,這和所有程式語言的約定類似。

step 表示步長,因此 step 使用負數沒有意義。

下面程式碼示範了使用 start、end 獲取元組中間一段的用法:
a_tuple = ('crazyit', 20, 5.6, 'fkit', -17)
# 存取從第2個到倒數第4個(不包含)所有元素
print(a_tuple[1: 3]) # (20, 5.6)
# 存取從倒數第3個到倒數第1個(不包含)所有元素
print(a_tuple[-3: -1]) # (5.6, 'fkit')
# 存取從第2個到倒數第2個(不包含)所有元素
print(a_tuple[1: -2]) # (20, 5.6)
# 存取從倒數第3個到第5個(不包含)所有元素
print(a_tuple[-3: 4]) # (5.6, 'fkit')
如果指定 step 引數,則可間隔 step 個元素再取元素。例如如下程式碼:
b_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9)
# 存取從第3個到第9個(不包含)、間隔為2的所有元素
print(b_tuple[2: 8: 2]) # (3, 5, 7)
# 存取從第3個到第9個(不包含)、間隔為3的所有元素
print(b_tuple[2: 8: 3]) # (3, 6)
# 存取從第3個到倒數第2個(不包含)、間隔為3的所有元素
print(b_tuple[2: -2: 2]) # (3, 5, 7)

加法

列表和元組支援加法運算,加法的和就是兩個列表或元組所包含的元素的總和。

需要指出的是,列表只能和列表相加;元組只能和元組相加;元組不能直接和列表相加。

如下程式碼示範了元組和列表的加法運算:
a_tuple = ('crazyit' , 20, -1.2)
b_tuple = (127, 'crazyit', 'fkit', 3.33)
# 計算元組相加
sum_tuple = a_tuple + b_tuple
print(sum_tuple) # ('crazyit', 20, -1.2, 127, 'crazyit', 'fkit', 3.33)
print(a_tuple) # a_tuple並沒有改變
print(b_tuple) # b_tuple並沒有改變
# 兩個元組相加
print(a_tuple + (-20 , -30)) # ('crazyit', 20, -1.2, -20, -30)
# 下面程式碼報錯:元組和列表不能直接相加
#print(a_tuple + [-20 , -30])
a_list = [20, 30, 50, 100]
b_list = ['a', 'b', 'c']
# 計算列表相加
sum_list = a_list + b_list
print(sum_list) # [20, 30, 50, 100, 'a', 'b', 'c']
print(a_list + ['fkit']) # [20, 30, 50, 100, 'fkit']

乘法

列表和元組可以和整數執行乘法運算,列表和元組乘法的意義就是把它們包含的元素重複 N 次(N 就是被乘的倍數)。

如下程式碼示範了列表和元組的乘法:
a_tuple = ('crazyit' , 20)
# 執行乘法
mul_tuple = a_tuple * 3
print(mul_tuple) # ('crazyit', 20, 'crazyit', 20, 'crazyit', 20)
a_list = [30, 'Python', 2]
mul_list = a_list * 3
print(mul_list) # [30, 'Python', 2, 30, 'Python', 2, 30, 'Python', 2]
當然,也可以對列表、元組同時進行加法、乘法運算。例如,把使用者輸入的日期翻譯成英文表示形式,即新增英文的“第”字尾。對於 1、2、3 來說,英文的“第”字尾分別用 st、nd、rd 代表,其他則使用 th 代表。

為此,可使用如下程式碼來完成該轉換:
# 同時對元組使用加法、乘法
order_endings = ('st', 'nd', 'rd')
    + ('th',) * 17 + ('st', 'nd', 'rd')
    + ('th',) * 7 + ('st',)
# 將會看到st、nd、rd、17個th、st、nd、rd、7個th、st
print(order_endings)
day = input("輸入日期(1-31):")
# 將字串轉成整數
day_int = int(day)
print(day + order_endings[day_int - 1])
該程式中,同時對 ('th',) 元組使用了乘法,再將乘法得到的結果使用加法連線起來,最終得到一個元組,該元組共有 31 個元素。

可能有讀者對 ('th',) 這種寫法感到好奇,此處明明只有一個元素,為何不省略逗號?這是因為 ('th') 只是字串加上圓括號,並不是元組,也就是說,('th') 和 'th' 是相同的。為了表示只有一個元素的元組,必須在唯一的元組元素之後新增英文逗號。

執行上面程式,可以看到如下執行結果:

輸入日期(1-31):27
27th

從上面的執行結果可以看出,使用者輸入 27,程式通過元組為 27 新增了“th”字尾。

in 運算子

in 運算子用於判斷列表或元組是否包含某個元素,例如如下程式碼:
a_tuple = ('crazyit' , 20, -1.2)
print(20 in a_tuple) # True
print(1.2 in a_tuple) # False
print('fkit' not in a_tuple) # True

長度、最大值和最小值

Python 提供了內建的 ten()、max()、min() 全域性函數來獲取元組或列表的長度、最大值和最小值。

由於 max()、min() 要對元組、列表中的元素比較大小,因此程式要求傳給 max()、min() 函數的元組、列表的元素必須是相同型別且可以比較大小。例如如下程式碼:
# 元素都是數值的元組
a_tuple = (20, 10, -2, 15.2, 102, 50)
# 計算最大值
print(max(a_tuple)) # 102
# 計算最小值
print(min(a_tuple)) # -2
# 計算長度
print(len(a_tuple)) # 6
# 元素都是字串的列表
b_list = ['crazyit', 'fkit', 'Python', 'Kotlin']
# 計算最大值(依次比較每個字元的ASCII碼值,先比較第一個字元,若相同,繼續比較第二個字元,以此類推)
print(max(b_list)) # fkit(26個小寫字母的ASCII碼為97~122)
# 計算最小值
print(min(b_list)) # Kotlin (26個大寫字母的ASCII碼為65~90)
# 計算長度
print(len(b_list)) # 4
在上面程式碼中,首先使用 3 個函數對元素都是數值的元組進行處理,可以看到程式獲取元組的最大值、最小值等。程式後半部分使用 3 個函數對元素都是宇符串的列表進行處理,也可以看到程式獲取列表的最大值、最小值等,這說明 Python 的字串也是可比較大小的,即 Python 依次按字串中每個字元對應的編碼來比較字串的大小。

序列封包和序列解包

Python 還提供了序列封包(Sequence Packing)和序列解包(Sequence Unpacking)的功能。簡單來說,Python 允許支援以下兩種賦值方式:
  • 程式把多個值賦給一個變數時,Python 會自動將多個值封裝成元組。這種功能被稱為序列封包
  • 程式允許將序列(元組或列表等)直接賦值給多個變數,此時序列的各元素會被依次賦值給每個變數(要求序列的元素個數和變數個數相等)。這種功能被稱為序列解包

下面程式碼示範了序列封包和序列解包的功能:
# 序列封包:將10、20、30封裝成元組後賦值給vals
vals = 10, 20, 30
print(vals) # (10, 20, 30)
print(type(vals)) # <class 'tuple'>
print(vals[1]) # 20
a_tuple = tuple(range(1, 10, 2))
# 序列解包: 將a_tuple元組的各元素依次賦值給a、b、c、d、e變數
a, b, c, d, e = a_tuple
print(a, b, c, d, e) # 1 3 5 7 9
a_list = ['fkit', 'crazyit']
# 序列解包: 將a_list序列的各元素依次賦值給a_str、b_str變數
a_str, b_str = a_list
print(a_str, b_str) # fkit crazyit
如果在賦值中同時運用了序列封包和序列解包機制,就可以讓賦值運算子支援同時將多個值賦給多個變數。例如如下程式碼:
# 將10、20、30依次賦值給x、y、z
x, y, z = 10, 20, 30
print(x, y, z) # 10 20 30
上面程式碼實際上相當於如下執行過程:
#先執行序列封包
xyz = 10,20,30
#再執行序列解包
x,y,z = xyz
使用這種語法也可以實現交換變數的值,例如如下程式碼:
# 將y,z, x依次賦值給x、y、z
x, y, z = y, z, x
print(x, y, z) # 20 30 10
在序列解包時也可以只解出部分變數,剩下的依然使用列表變數儲存。為了使用這種解包方式,Python 允許在左邊被賦值的變數之前新增“*”,那麼該變數就代表一個列表,可以儲存多個集合元素。例如如下程式:
# first、second儲存前2個元素,rest列表包含剩下的元素
first, second, *rest = range(10)
print(first) # 0
print(second) # 1
print(rest) # [2, 3, 4, 5, 6, 7, 8, 9]
# last儲存最後一個元素,begin儲存前面剩下的元素
*begin, last = range(10)
print(begin) # [0, 1, 2, 3, 4, 5, 6, 7, 8]
print(last) # 9
# first儲存第一個元素,last儲存最後一個元素,middle儲存中間剩下的元素
first, *middle, last = range(10)
print(first) # 0
print(middle) # [0, 1, 2, 3, 4, 5, 6, 7, 8]
print(last) # 9