1. 程式人生 > >Python 6-1.內建資料結構之list(基礎篇)

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為第四個
結果如下:
123
 -分片操作-
  • 注意擷取範圍,一般來說有開始和結束兩個下標值都是包括左不包括右
 案例如下
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))
結果如下:
140723906273408
140723906276608

     我們對比c和b的編碼,可以看出c和b並不是同一身份,而a和c確實統一身份,這就涉及到傳值和傳址

c = a
print(id(c))
結果如下:
140723906273408

這裡更改了a的值,按照邏輯,c的值也應該更改,但是我們看編碼,c的值並沒有發生變化,這就是順序結構的影響,c所接收的值是還沒更改的a的值,再a更改過後,c並未接收到指令需要再次更改

a = 101
print(id(a))
print(id(c)) 
結果如下:
140723906273440
140723906273408

     當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完全一致
結果如下:
1425021100616
1425021100680
1425021100616

     我們再次通過修改列表的內容,來證實

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))  # 刪除後
結果如下:
1617250837064
1617250837064
 從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))
結果如下:
99
 求列表中最大值 mxn(list)求列表最大值
a = [x for x in range(1,100)]
print(max(a))
結果如下:
99
 求列表中最小值 min(list)求列表最小值
a = [x for x in range(1,100)]
print(min(a))
結果如下:
1
 如果獲取列表最大值的型別為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())
結果如下:
9
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))
結果如下:
1296231391816
1296231391816
 直接賦值的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))
結果如下:
1312161292872
1312161292936
 通過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))
結果如下:
2354867757704
2354868916552
 這時使用id函式訪問a列表裡面的雙層列表
print(id(a[3]))
print(id(b[3]))
結果如下:
2869806391880
2869806391880
 由此可見,淺拷貝無法拷貝雙層列表裡面的內容 我們通過修改來檢視區別 修改雙層列表內容
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]))
結果如下:
1724958056840
1724958057160
 這時雙層列表內容的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型別的兩個變數編碼的變化
結果如下:

11407239062702401407239062734401011140723906270240[1, 2, 3, 4, 5]24312343025362431234302536[1, 2, 100, 4, 5][1, 2, 100, 4, 5]2431234302536

 我們可以看到兩個函式,經過函式改變之後,函式區域性列印和全域性列印列表是一致的,