Python 6-1.內建資料結構之list(基礎篇)
-常見內建資料結構- list 列表 set集合 dict 字典 tuple 元祖 -本章大綱-
-
list(列表): 一組由順序的資料的組合 建立列表 有值列表 無值列表(空列表) 使用list建立列表 修改列表值 列表常用操作 訪問列表 使用下標操作(索引),大部分語言索引都是從0開始 列表位置從0開始 語法: list[val] 分片操作(擷取操作) 從列表裡擷取任意一段 語法: list[開始:結束] del(刪除命令) 列表的連線 使用乘加來對列表操作 列表成員資格運算 列表的遍歷使用 使用for和while來遍歷,對比過程 雙層列表迴圈 列表內涵:list content 關於列表的常用函式 len(list)獲取列表長度 mxn(list)求列表最大值 min(list)求列表最小值 list(str)把字串拆分成字元並存入列表裡面 list.append(val)在列表尾部追加內容 list.insert(index,val)在指定下標前面插入內容 list.pop(index) 取出指定下標的值 list.remove(index.max)刪除指定下標的內容 list.clear()清空列表裡面的內容 list.reverse()f翻轉列表類容,原地翻轉地址不變 list.extend(list2)拓展列表,把一個列表拼接到另一個後面 list.count()查詢列表中相同指定值或元素的數量 list.copy()淺拷貝 copy.deepcopy(list)深拷貝
空列表案例
l1 = [] print(type(l1)) print(l1)
結果如下:
<class 'list'> []
帶值列表案例
l2 = ["1","2","lalla","啦啦啦"] print(type(l2)) print(l2)
結果如下:
<class 'list'> ['1', '2', 'lalla', '啦啦啦']
使用list()來建立空列表
l3 = list() print(type(l3)) print(l3)
結果如下:
<class 'list'> []
修改列表內容
l = [1,2,3,4,5] print(l)# 修改前 l[1] = 100 print(l[:])# 修改後
結果如下:
[1, 2, 3, 4, 5] [1, 100, 3, 4, 5]
修改一部分列表的內容
l = [1,2,3,4,5] print(l)# 修改前 l[1:3] = 100,200 print(l)# 修改後
結果如下:
[1, 2, 3, 4, 5] [1, 100, 200, 4, 5]
-列表常用操作- 訪問列表 使用下標操作(索引),大部分語言索引都是從0開始 列表位置從0開始 語法: list[val] 分片操作(擷取操作) 從列表裡擷取任意一段 語法: list[開始:結束] del(刪除命令) 列表的連線 使用乘加來對列表操作 列表成員資格運算 列表的遍歷使用 使用for和while來遍歷,對比過程 雙層列表迴圈 列表內涵:list content 關於列表的常用函式
下標訪問列表案例
l = [1,2,4,123,3] print(l[3]) #下標從0開始,所以擷取的下標3為第四個
結果如下:
-分片操作-
- 注意擷取範圍,一般來說有開始和結束兩個下標值都是包括左不包括右
案例如下
l = [1,2,4,123,3] print(l[1:4])#擷取從第二個到第四個
結果如下:
[2, 4, 123]
下標值可以為空,如果不屑,左邊下標值預設為0,右邊下標值預設為最大數加一,也就是說擷取到最後一位
注意最終列印的結果
左右下標完全不寫
l = [1,2,4,123,3] print(l[:])
結果如下:
[1, 2, 4, 123, 3]
只寫左邊下標
l = [1,2,4,123,3] print(l[1:])
結果如下:
[2, 4, 123, 3]
只寫右邊下標
l = [1,2,4,123,3] print(l[:4])
結果如下:
[1, 2, 4, 123]
分片操作可以控制增長幅度,預設增長幅度為1
l = [1,2,4,123,3] print(l[1:6:1])
結果如下:
[2, 4, 123, 3]
列印從下標1到4的數字,每次遍歷中間隔開一個
l = [1,2,4,123,3] print(l[1:4:2])
結果如下:
[2, 123]
下標索引可以超出範圍,不過超出後不會提示錯誤並且不考慮多餘下標內容
l = [1,2,4,123,3] print(l[1:100])
結果如下:
[2, 4, 123, 3]
-下標值和增長幅度可以為負數-
- 當下標值為負數時,索引遍歷的順序就會相反,即從右到左
- 當下標值為負數時,列表裡最後的內容下標為-1
分片操作 下標值為負,案例如下 無論下標值是否為負,左邊的下標值一定要比右邊的下標值小
l = [1,2,4,123,3] print(l[-2:-4])#執行結果為空 print(l[-4:-2])
結果如下:
[] [2, 4]
如果分片的左邊下標值一定要比右邊下標值大,則增長幅度要使用負數 此案例為一個list直接正反顛覆提供了一種思路
l = [1,2,4,123,3] print(l[-2:-4:-1])
結果如下:
[123, 4]
-分片操作是生成一個新的list-
- 內建函式id,負責顯示一個遍歷或資料的唯一確定編碼
id函式案例如下
a = 100 b = 200
兩個變數不能通過值來對其身份判斷
可以通過id函式獲取編碼進行對比
print(id(a)) print(id(b))
結果如下:
我們對比c和b的編碼,可以看出c和b並不是同一身份,而a和c確實統一身份,這就涉及到傳值和傳址
c = a print(id(c))
結果如下:
這裡更改了a的值,按照邏輯,c的值也應該更改,但是我們看編碼,c的值並沒有發生變化,這就是順序結構的影響,c所接收的值是還沒更改的a的值,再a更改過後,c並未接收到指令需要再次更改
a = 101 print(id(a)) print(id(c))
結果如下:
當c再次接收指令需要更改值時的編碼
c = a print(id(a)) print(id(c)) print(id(a)==id(c)) #返回的結果為true
結果如下:
140723906273440 140723906273440 True
使用id內建函式來判斷擷取的list是否是新生成的列表
l = [3,2,1,23,3] ll = l[:] #通過擷取方式賦值 lll = l #直接進行賦值
對比三者的編碼
print(id(l)) print(id(ll)) print(id(lll)) #很明顯,直接賦值的編碼跟原來的list完全一致
結果如下:
我們再次通過修改列表的內容,來證實
l[1] = 100 print(l) print(ll) print(lll)
結果如下:
[3, 100, 1, 23, 3] [3, 2, 1, 23, 3] [3, 100, 1, 23, 3]
通過結果可以看出擷取的list並未發生任何變化,反之直接賦值的list就跟原本list發生了相同的變化,這又是傳值和傳址的問題
-del 刪除命令-
- 語法:
- del 列表名稱[需要刪除內容的下標]
刪除案例如下:
a = [1,2,3,4,5] del a[2] print(a)
結果如下:
[1, 2, 4, 5]
利用id內建函式檢視刪除過後的list是否還是原來的列表,還是系統給重新生成了一個
a = [1,2,3,4,5] print(id(a))# 刪除前 del a[2] print(id(a))# 刪除後
結果如下:
從id給的編碼看得出來,並沒有不同,證明刪除的內容是直接從list裡刪除,而不是將不需要刪除的內容重新放置到一個新的list裡面 del刪除了一個變數之後不能再繼續使用該變數
a = [1,2,3,4,5] del a print(a) #刪除列表型別的變數 b = 1 del b print(b) #刪除普通變數
結果如下:
Traceback (most recent call last): File "D:/圖靈/2.基礎語法/測試.py", line 3, in <module> print(a) #刪除列表型別的變數 NameError: name 'a' is not defined
無論刪除任何型別的變數,後面都不能再繼續使用該變數
-列表的連線使用-
- 使用算術運算子進行連結
使用加號連線兩個列表
a = [1,2,3,4,5] b = [6,7,8,9,10] c = a + b print(c)
結果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
使用乘號操作列表
a = [1,2,3,4,5] b = a * 3 print(b)
結果如下:
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
得到的值相當於n和相同的列表相加 列表成員資格運算
- 使用in成員運算子進行操作(關於in函式前面"表示式章節有講")
使用in進行操作
a = [1,2,3,4,5] b = 8 print(b in a) #返回值為布林值
結果如下:
False
使用not in進行操作
a = [1,2,3,4,5] b = 8 print(b not in a)
結果如下:
True
-列表的遍歷-
- for
- while(凡是關於遍歷的大都不推薦)
使用for進行遍歷操作 案例如下
a = [1,2,3,4,5] for i in a: print(i) #通過遍歷列印 #對比兩種列印之後值的型別 print(type(i)) print(a) #直接列印 print(type(a))
結果如下:
1 <class 'int'> 2 <class 'int'> 3 <class 'int'> 4 <class 'int'> 5 <class 'int'> [1, 2, 3, 4, 5] <class 'list'>
通過遍歷列印和直接列印的最大區別是,前者把整個列表拆散,一個一個去訪問裡面的值然後進行列印,後者直接看作一個整體進行列印 我們可以看到遍歷列印之後的值是int型別,而直接遍歷的值為list類,看得出來拆分過後的值型別是按照原本它在列表時的型別進行輸出 有個很有意思的東西,分享給大家,這是大拿老師分享給我們的 不常寫python程式碼的程式員寫的python程式碼是這樣的
a = [1,2,3,4,5] for i in range(0,len(a)): #他們會把a(列表)看成一個值,把列表的內容獲取之後存入range再通過for進行列印 print(a[i]) i += 1
使用while迴圈訪問list(麻煩死了=-=) 不推薦使用while遍歷list len(list,tuple,dict)=返回物件(字元、列表、元組等)長度或專案個數
a = [1,2,3,4,5] #定義index表示list的下標 index = 0 while index < len(a): print(type(a[index])) print(a[index]) #將第index個a進行列印 index += 1 #讓下標每遍歷一次就進行下一個下標的遍歷
結果如下:
<class 'int'> 1 <class 'int'> 2 <class 'int'> 3 <class 'int'> 4 <class 'int'> 5
-雙層列表迴圈-
a = [["zhansan",12,"遊戲"],["lisi",13,"游泳"],["wangwu",15,"籃球"]]
列印方法:每個列表有多少個值就用多少個變數進行帶出
for k,v,w in a: print(k,"--",v,"--",w)
結果如下:
zhansan -- 12 -- 遊戲 lisi -- 13 -- 游泳 wangwu -- 15 -- 籃球
迴圈變數的個數應該於列表解包出來的變數個數一致
a = [["zhansan",12,"遊戲"],["lisi",13,"游泳"],["wangwu",15,"籃球",1,2,3,4,]]
列印方法:每個列表有多少個值就用多少個變數進行帶出,否則就會出錯
for k,v,w in a: print(k,"--",v,"--",w)
結果如下:
Traceback (most recent call last): zhansan -- 12 -- 遊戲 lisi -- 13 -- 游泳 File "D:/圖靈/2.基礎語法/測試.py", line 2, in <module> for k,v,w in a: ValueError: too many values to unpack (expected 3)
-列表內涵:list content-
- 通過簡單方法創作列表
通過for遍歷出來的值放置到一個新的列表裡面來形成一個列表
a = [1,2,3,4] #通過list a 來建立新的list b b = [i for i in a] print(a) print(b) #對比id編碼是否相等 print(id(a)) print(id(b))
結果如下:
[1, 2, 3, 4] [1, 2, 3, 4] 1651187802696 1651187802760
通過程式碼我們可以看出就算b列表的值是從a列表裡面獲得的,但是編碼顯示它們不是同一個變數 在生成新的列表時,使用乘號對列表值進行操作 案例條件:讓b裡面的所有值乘以10
a = [1,2,3,4,5] b = [i*10 for i in a] print(a) print(b)
結果如下:
[1, 2, 3, 4, 5] [10, 20, 30, 40, 50]
還可以通過演算法將過濾的內容放置新列表 使用for i in range生成從1到34的列表a,將列表a裡面的偶數生成一個列表b
a = [i for i in range(1,34)] b = [r for r in a if r%2 == 0] print(a) print(b)
結果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33] [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32]
列表生成式可以巢狀
a = [i for i in range(1,5)] #生成 list a b = [i for i in range(100,500) if i % 100 == 0]
將a和b列表裡面的值對應相加並且放置新列表c裡面 n將a列表內容逐個遍歷,m將b列表內容逐個遍歷
c = [n+m for n in a for m in b] #分別列印a,b,c列表對比內容 print(a) print(b) print(c)
結果如下:
[1, 2, 3, 4] [100, 200, 300, 400] [101, 201, 301, 401, 102, 202, 302, 402, 103, 203, 303, 403, 104, 204, 304, 404]
將c裡面的表示式詳細版:案例如下 其實就是個巢狀迴圈
for n in a: for m in b: print(m+n,end=" ") #end是print內建函式的一個引數,規定空格,預設值end="\n" help(print) #檢視print的官方幫助文件,help(函式名) = 檢視該函式的官方幫助文件
結果如下:
101 201 301 401 102 202 302 402 103 203 303 403 104 204 304 404 Help on built-in function print in module builtins: print(...) print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) Prints the values to a stream, or to sys.stdout by default. Optional keyword arguments: file:a file-like object (stream); defaults to the current sys.stdout. sep:string inserted between values, default a space. end:string appended after the last value, default a newline. flush: whether to forcibly flush the stream.
-列表的常用函式-
- len(list)獲取列表長度
- mxn(list)求列表最大值
- min(list)求列表最小值
- list(str)把字串拆分成字元並存入列表裡面
- list.append(val)在列表尾部追加內容
- list.insert(index,val)在指定下標前面插入內容
- list.pop(index) 取出指定下標的值
- list.remove(index.max)刪除指定下標的內容
- list.clear()清空列表裡面的內容
- list.reverse()f翻轉列表類容,原地翻轉地址不變
- list.extend(list2)拓展列表,把一個列表拼接到另一個後面
- list.count()查詢列表中相同指定值或元素的數量
- list.copy()淺拷貝
- copy.deepcopy(list)深拷貝
求列表長度 len(list)獲取列表長度
a = [x for x in range(1,100)] print(len(a))
結果如下:
求列表中最大值 mxn(list)求列表最大值
a = [x for x in range(1,100)] print(max(a))
結果如下:
求列表中最小值 min(list)求列表最小值
a = [x for x in range(1,100)] print(min(a))
結果如下:
如果獲取列表最大值的型別為str,則選擇字元最長的為最大值
a = ["a","ab","abc"] print(max(a)) # min同理 print(min(a))
結果如下:
abc a
list(str)把字串拆分成字元並存入列表裡面
s = "Baby, there's nothing holding me back" print(list(s))
結果如下:
['B', 'a', 'b', 'y', ',', ' ', 't', 'h', 'e', 'r', 'e', "'", 's', ' ', 'n', 'o', 't', 'h', 'i', 'n', 'g', ' ', 'h', 'o', 'l', 'd', 'i', 'n', 'g', ' ', 'm', 'e', ' ', 'b', 'a', 'c', 'k']
把range產生的內容轉化成list list(range(start,stop))
print(list(range(1,10)))
結果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
list.append(val)在列表尾部追加內容
a = [i for i in range(1,10)] print(a) #追加前 a.append(100) print(a) #追加後
結果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9] [1, 2, 3, 4, 5, 6, 7, 8, 9, 100]
list.insert(index,val)在指定下標前面插入內容
a = [i for i in range(1,10)] print(a) a.insert(3,100) #在下標為3的前面插入一個內容 print(a)
結果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9] [1, 2, 3, 100, 4, 5, 6, 7, 8, 9]
刪除
- del 和 pop的區別,前者為直接刪除,後者為取出
del刪除,直接在列表裡面刪除
a = [i for i in range(1,10)] print(a) del a print(a) #刪除之後無法呼叫
結果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9] Traceback (most recent call last): File "D:/圖靈/2.基礎語法/測試.py", line 4, in <module> print(a) #刪除之後無法呼叫 NameError: name 'a' is not defined
pop則是從對應的下標位置取出一個元素,取出的元素為最後一個
a = [i for i in range(1,10)] print(a.pop())
結果如下:
list.remove(index.max)刪除指定下標的內容
- 如果被指定要刪除的值沒在list中,則會報錯
- 所以在使用remove時,最好使用先行判斷
檢視remove操作時直接從列表裡面進行刪除,還是將值取出來放置到一個新的list裡面
a = [i for i in range(1,10)] print(id(a))# 刪除前 aa = 8 #指定一個值 if aa in a: a.remove(aa) print(a) print(id(a))# 刪除後
結果如下:
2721021846088 [1, 2, 3, 4, 5, 6, 7, 9] 2721021846088
list.clear()清空列表裡面的內容
使用clear來清空,我們可以看到列表還在,而且裡面的地址也是一致的
a = [i for i in range(1,10)] print(a) print(id(a)) a.clear() print(a) print(id(a))
結果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9] 2428798329416 [] 2428798329416
如果不計較地址問題時,我們可以直接使用空的list去替換掉,但這時地址就不一致了
a = [] print(a) print(id(a))
結果如下:
[] 2158892847240
list.reverse()f翻轉列表類容,原地翻轉地址不變
a = [1,2,3,4,5] print(a)# 翻轉前 print(id(a)) a.reverse() print(a)# 翻轉後 print(id(a))# 翻轉過後還是同一個列表
結果如下:
[1, 2, 3, 4, 5] 2783136211528 [5, 4, 3, 2, 1] 2783136211528
list.extend(list2)拓展列表,把一個列表拼接到另一個後
a = [1,2,3,4] b = [6,7,8,9,10] print(a) #拼接前 print(id(a)) a.extend(b) print(a)# 拼接後 print(id(a)) print(a+b) #使用拼接手法來拓展列表,能使拓展列表原來的地址儲存,而直接相加來拓展,則會生成一個新的列表 print(id(a+b))
結果如下:
[1, 2, 3, 4] 2219187266120 [1, 2, 3, 4, 6, 7, 8, 9, 10] 2219187266120 [1, 2, 3, 4, 6, 7, 8, 9, 10, 6, 7, 8, 9, 10] 2219216318920
list.count()查詢列表中相同指定值或元素的數量
a = [1,2,3,3,4,2] print(a) print(a.count(2)) #列表中有兩個2
結果如下:
[1, 2, 3, 3, 4, 2] 2
copy:拷貝,此函式是淺拷貝 關於拷貝和直接賦值的區別 直接賦值案例:
a = [1,2,3,4,5] b = a print(id(a)) print(id(b))
結果如下:
直接賦值的id是一致的,那就是說無論在何處修改修改a或b另一個都會發生改變
b[3] = 111 print(a) print(b)
結果如下:
[1, 2, 3, 111, 5] [1, 2, 3, 111, 5]
拷貝案例
a = [1,2,3,4,5] b = a.copy() print(id(a)) print(id(b))
結果如下:
通過a拷貝的b列表裡面的id與a列表完全不符合,這就可以在修改a或b時不會影響到另一個列表了
a[1] = 888 print(a) print(b)
結果如下:
[1, 888, 3, 4, 5] [1, 2, 3, 4, 5]
淺拷貝和深拷貝的區別 copy函式只是個淺拷貝函式,只拷貝一層內容
a = [1,2,3,[1,2,3,4]] b = a.copy() print(id(a)) print(id(b))
結果如下:
這時使用id函式訪問a列表裡面的雙層列表
print(id(a[3])) print(id(b[3]))
結果如下:
由此可見,淺拷貝無法拷貝雙層列表裡面的內容 我們通過修改來檢視區別 修改雙層列表內容
a[3][2] = 636 print(a) print(b)
結果如下:
[1, 2, 3, [1, 2, 636, 4]] [1, 2, 3, [1, 2, 636, 4]]
修改列表內容
a[3][2] = 111 print(a) print(b)
結果如下:
[1, 2, 3, [1, 2, 111, 4]] [1, 2, 3, [1, 2, 111, 4]]
只有雙層列表裡面的內容可以被修改 使用深拷貝來拷貝雙層列表 引入copy庫
import copy a = [1,2,3,[1,2,3,4]] b = copy.deepcopy(a) print(a) print(id(a)) print(b) print(id(b))
結果如下:
[1, 2, 3, [1, 2, 3, 4]] 2427933269384 [1, 2, 3, [1, 2, 3, 4]] 2427933267848
再檢視雙層列表的id
print(id(a[3])) print(id(b[3]))
結果如下:
這時雙層列表內容的id也發生了變化 通過改變a雙層列表裡面的內容來觀察變化
a[3][2] = 666 print(a) print(b)
結果如下:
[1, 2, 3, [1, 2, 666, 4]] [1, 2, 3, [1, 2, 3, 4]]
這時b列表的雙層列表並沒有發生變化,這就是淺拷貝和深拷貝的區別
關於傳值和傳址的區別
def int(n): n += 100 print(id(n)) print(n) def list(n): n[2] = 100 print(id(n)) print(n) return None n1 = 1 n2 = [1, 2, 3, 4, 5] print(n1) print(id(n1)) int(n1) print(n1) print(id(n1)) print(n2) print(id(n2)) list(n2) print(n2) print(id(n2))
我們觀察在呼叫函式前和呼叫函式後,int和list型別的兩個變數編碼的變化
結果如下:
1 140723906270240 140723906273440 101 1 140723906270240 [1, 2, 3, 4, 5] 2431234302536 2431234302536 [1, 2, 100, 4, 5] [1, 2, 100, 4, 5] 2431234302536
我們可以看到兩個函式,經過函式改變之後,函式區域性列印和全域性列印列表是一致的,反之int方面則不同 因為對於列表來說傳入的引數為傳址,所以在全域性列印時訪問的地址和區域性的相同,則列印的內容也相同 而int傳入的引數為傳值,因為區域性訪問時訪問的是引數的值,當全域性訪問時無法獲得經過函式改之後引數的值,所以值沒發生改變
文筆不好,僅供參考
要有錯誤或者有其他更多的見解,歡迎大家加我QQ384435742來交流
想第一時間看更新的文章,請關注,謝謝