用戶:Xyy23330121/Python/列表和元組
Python 中還提供了兩種好用的序列:列表和元組。其中列表是可變序列,而元組和字符串一樣是不可變序列。
用方括號括起來,不被解釋為索引的的內容會被視為列表,列表是由一系列變量組成的,每個變量之間由逗號,
分隔。
a = [0, 1, 'string'] #创建一个列表,列表中可以包含任意的不同变量。
print(a) #输出:[0, 1, 'string']
b = [] #可以创建空列表。
需要特別強調,列表中的元素也可以是一個列表。
c = [[0, 1], 2]
用括號括起來,由多個用逗號隔開的值組成的是元組。
a = (0, 1, 'string') #创建一个元组,元组中可以包含任意的不同变量。
print(a) #输出:(0, 1, 'string')
b = () #可以创建空元组
需要特別強調,元組中的元素也可以是一個元組或列表。
c = ((0, 1), 2)
理解 Python 文檔的一個簡單方法是:把逗號當成優先級比「賦值」高的運算符。比如:1, 2, 3
運算的結果是返回一個元素為1
、2
和3
的元組。
為了和一般的表達式區分開,創建只有一個元素的元組時,需要在元素後加一個括號,比如:
d = (0,)
為了方便起見,有2個或多個元素的元組,在不引發歧義的情況下,可以不加括號。
e = 0, 1
f = (0, 1), 2 #此时,作为 f 第一个元素的元组,必须要加括号。
前面賦值方法章節提到的序列解包,就是對元組進行的操作。
類似 int
、float
等函數的行為,list
函數 / tuple
函數可以用於創建列表/元組。
a = list()
b = tuple()
不傳入任何參數的情況下,生成的是空列表/空元組。
可以簡單認為,既有多個元素,又有順序的對象都是可迭代對象。
a = list((1, 2, 3))
b = tuple([1, 2, 3])
任何可迭代對象都可以作為 list
函數 / tuple
函數的參數。
大多數序列類型,包括可變序列和不可變序列都支持下面的操作。列表和元組就支持下面的操作。
a = (1,)
b = (2,)
c = (3,)
a+b+c
Python 會先計算a+b
,在內存中存入(1, 2)
;然後再計算(1, 2)+c
,在內存中存入(1, 2, 3)
。在計算時存儲的總內容為:
a
b
c
(1, 2)
(1, 2, 3)
,即 8 個元組中元素的內存。通過模擬可以得出,運算時內存的佔用,和元素所需總內存的平方是同階的。
為此,如果要連續拼接此類對象,應當使用 Python 為這些對象提供的方法,或者轉化為可變序列。比如:
- 拼接字符串時,應當先構建由字符串組成的列表,再用
str.join
方法。 - 拼接元組時,應當先將元組轉化為列表,再用
+=
運算符擴展列表。 - 拼接bytes對象時,可以用
bytes.join
方法,也可以轉化為bytearray再用+=
進行原地拼接。
+=
運算符擴展列表,參見下面的內容。關於 bytes 和 bytearray,參見「字符串和編碼」章節。類似字符串,兩個列表相加、或兩個元組相加,返回的是拼接之後的結果;而列表或元組和整數n
作乘法,返回的是重複 n 次後的結果。
print([1,2] + [3]) #加法:返回拼接之后的结果。
print((1,2) + (3,))
print([1,2] * 3) #整数乘法:返回原列表/元组重复 n 次的结果。
print((1,2) * 3)
除此之外,還有許多操作和字符串的結果類似。
a,b = [1, 2, 3], (1, 2, 3)
print(len(a),len(b)) #可以通过 len() 得到列表/元组的长度。
print(a[2],b[2]) #列表/元组支持索引。索引的方式和字符串类似。
print(a[::2],b[::2])
但是,和字符串返回對應位置的單個字符組成的子字符串不同,在使用整數作索引時,列表或元組會返回對應位置的元素,而非返回子列表或子元組。只有使用 slice 作索引時,總會返回一個子列表或子元組。
print(1 in a, 1 not in b) #可以用比较表达式 in / not in 判断元素是否在列表/元组中。
和字符串不同,in
和 not in
只判斷元素是否是列表/元組的元素,不會判斷子列表/子元組是否在原列表/原元組內。比如:
print([0,1] in [0,1,2]) #输出:False
print((0,1) in (0,1,2)) #输出:False
print("01" in "012") #输出:True
a = (0, 1, 2)
b = [0, 1, 2]
print(max(a), min(b)) #输出:2 0
max
函數和 min
函數可以對序列中的元素進行比較。但這要求序列中所有元素之間兩兩可以比較。
a = (0, 1, 2, 2, 3, 2)
b = [0, 1, 2, 2, 3, 2]
print(a.index(2, 3, 5), b.count(2)) #输出:3 3
s.index(value[, start[, stop]])
的運行結果等同於 s[start:stop].index(value)
,會輸出範圍內第一個等於 value
的元素的索引。
s.count(value)
和字符串不同,不支持 start
和 stop
兩個參數。它會輸出整個列表中,該元素的個數。
除上面的操作之外,一個常用的操作是用推導式創建列表或元組。以下是一個簡單示例:
iterable = "Python"
s = [x for x in iterable]
t = (x for x in iterable)
此時,print(s,t)
輸出的結果是:
['P', 'y', 't', 'h', 'o', 'n'] ('P', 'y', 't', 'h', 'o', 'n')
對於 a for b in c
,Python 會把可迭代對象 c
中的第一個迭代元素賦值到 b
,然後把賦值後、表達式 a
的結果插入到列表或元組中。再把 c
中的第二個迭代元素賦值到 b
,然後把賦值後、表達式 a
的結果插入到列表或元組中。直到可迭代對象沒有下一個迭代元素為止。
在 a for b in c
後面,還可以添加 if d
。此時,在給 b
賦值後,只有表達式 d
的結果為 True
,才會把表達式 a
的結果插入到列表或元組中。比如以下形式:
iterable = "Python"
s = [x for x in iterable if x in "Thoughts"]
print(s) #输出:['t', 'h', 'o']
運算 | 解釋 | 示例 | |
---|---|---|---|
s[i] = x
|
給可變序列中,索引為 i 的元素賦值。如果索引為 i 的元素不存在,會報錯:IndexError: list assignment index out of range
|
||
輸出 | |||
s[i:j] = t
|
按給出的子序列替換可變序列的元素。 | ||
輸出 | |||
del s[i:j]
|
刪除序列中,在該子序列中的元素。 等同於 s[i: j] = [] 。
|
||
輸出 | |||
s[i:j:k] = t
|
替換可變序列的子序列。 此時 t 的長度必須與子序列長度相匹配。如果不匹配,會報錯 ValueError 。
|
||
輸出 | |||
del s[i:j:k]
|
刪除序列中,在該子序列中的元素。 | ||
輸出 | |||
s.append(x)
|
將元素 x 添加到序列的末尾。等同於 s[len(s):len(s)] = [x] 。
|
||
輸出 | |||
s.clear()
|
從 s 中移除所有項等同於 del s[:] 。
|
||
輸出 | |||
s.copy()
|
創建並返回 s 的副本。等同於 s[:] 。該方法的作用將在之後講解。 |
||
輸出 | |||
s.extend(t)
|
用可迭代對象 t 中的元素擴展 s 。
|
||
輸出 | |||
s += t
|
同s.extend(t) 。這裏不能簡單理解為 s = s + t 。
|
||
輸出 | |||
s *= n
|
結果等同於 s = s * n 。
|
||
輸出 | |||
s.insert(i, x)
|
在索引i 處插入元素。使 s[i] == x 。若索引 i < -len(s) ,則會插入在序列開頭。若索引 i >= len(s) ,則會插入在序列結尾。 |
||
輸出 | |||
s.pop(i)
|
移除索引為 i 的元素,並返回該元素的值。如果索引為 i 的元素不存在,則會報錯: IndexError: pop index out of
|
||
輸出 | |||
s.pop()
|
若 i 未給出,pop 方法默認移除最後一個元素。若序列為空序列,則會報錯: IndexError: pop from empty list
|
||
輸出 | |||
s.remove(x)
|
刪除 s 中第一個等於 x 的元素。若沒有符合標準的元素,則會報錯: ValueError: list.remove(x): x not
|
||
輸出 | |||
s.reverse()
|
反轉列表。 | ||
輸出 |
列表是可變序列,元組是不可變序列。可變序列均支持此表格中的操作。
list.sort()
方法會對列表中的元素進行排序。我們有以下示例:
s = [0, 3, 1, 4]
s.sort()
print(s) #输出:[0, 1, 3, 4]
s.sort(reverse = True)
print(s) #输出:[4, 3, 1, 0]
關於參數key
,我們將放在函數章節里學習。
在使用列表時,以下代碼可能不會得到想像中的結果:
a = [0, 1]
b = a
b[1] = 0
print(a)
這段代碼輸出的結果是[0, 0]
!說明在更改 b
的時候,a
也被同步更改了!
以下代碼的輸出也有類似的問題:
a = [[]]*3
a[0].append(1)
print(a) #输出[[1],[1],[1]]
如果讀者學習過 C 語言中關於指針的內容,可能很容易就能猜到原因。這裏不多講解原因,我們講講如何規避這樣的問題。
在 #列表的一些方法 章節中,有一個 s.copy()
方法。它可以用於解決上述問題的。我們將代碼改為:
a = [0, 1]
b = a.copy()
b[1] = 0
print(a) #输出:[0, 1]
就解決了問題。但這對於嵌套的列表而言不起作用,比如:
a = [[0,1], [2,3]]
b = a.copy()
b[1][0] = 0
print(a) #输出:[[0, 1], [0, 3]]
除 copy 方法外,我們還可以用推導式來複製列表。比如:
a = [0, 1]
b = [x for x in a]
b[1] = 0
print(a) #输出:[0, 1]
我們可以嵌套多個推導式,來複製嵌套的列表。比如:
a = [[0,1], [2,3]]
b = [[xx for xx in x] for x in a]
b[1][0] = 0
print(a) #输出:[[0, 1], [2, 3]]
就解決了問題。若已知列表是二維列表。也可以用:
a = [[0,1], [2,3]]
b = [x.copy() for x in a]
b[1][0] = 0
print(a) #输出:[[0, 1], [2, 3]]
也可以解決問題。
使用推導式方法加一點控制,我們事實上可以做任意維度嵌套列表的複製。以下內容在學習函數章節之前可能較難理解。
def copy(seq): return [(copy(obj) if isinstance(obj, list) else obj) for obj in seq]
a = [0,0,[1,1,[2,2,[3,3]]]]
b = copy(a)
b[2][2][2][0] = 4
print(a)
print(b)