清單
元素用方括号括起,元素之間用逗号隔開,如[1,2,3,4],不能一開始定義清單的大小
三大特點:
(1)異構性
清單裡想裝啥就裝啥,即:他可以包含不同種類、任意類型的對象,甚至可以嵌套清單
示例:
運作結果:
(2)有序性
清單裡裝的元素都是有順序的,可以按照位置序号(索引)擷取單個元素,也可以用分片的方法來進行多個連續元素的擷取
通路元素的方法:
a.索引
與其他語言中數組的索引通路方式相似,告訴位置即可,并且位置從0開始
不同于其他語言中的數組:python提供了負數索引,-1指定倒數第一個位置,-2,-3類推
示例:
運作結果:
b.切片
在方括号中指定要使用的第一個元素和最後一個元素的索引,中間用冒号隔開,如list[1:3] ,注意此處說的是索引,即冒号兩邊的是索引,是以是從0開始的
還有以下常見做法:
《1》如果省略掉終止索引,就表示一直截取到末尾:
《2》如果省略掉起始索引,就表示從起始元素就開始截取:
《3》可以使用負索引,也就是從右往左的索引,最右側是-1,向左依次為-2,-3
《4》要跳着截取,就需要多加一個冒号,第三個參數表示跳的步長,如list[0:5:2]
示例:
運作結果:
同時由示例可以注意到:當采用索引區間時,冒号右邊的位置的值不會被包含
跳着截取時,下一個元素的值為(前一個元素的位置+步長)的位置的值
疑問:如果對截取出的分片進行修改,會影響到原始的清單嗎?
示例:
運作結果:
對原始清單進行切片,産生一個全新的清單,用變量擷取該切片,實質上是擷取了list分片的新的獨立拷貝,是以對a的修改不會影響原始清單
(3)本地可修改(就是在自身修改)
清單的大小和内容可以随意改變,在插入、删除、修改清單元素時,不需要建立一份新的清單拷貝,而是在原來的記憶體位址上直接修改清單對象
a.修改元素
索引指派
與索引通路清單元素相似,直接給索引通路的值指派,如list[0]=8
切片指派:
list[1:3]=[1,2,3]
示例:
運作結果:
是以由上述示例可以看出,切片指派,與右邊界和=右邊的指派個數無關,本質是先删除切片位置的元素,再在該切片位置添加指定元素,
并且由list1可以看出,删除的時候也沒有删除右邊界的值,是以切片始終是左閉右開
b.添加元素
append() ------------------- 在清單的末尾添加元素
insert() ------------------- 在清單的任何位置添加新元素,需要指定索引和值,插入是就地修改,而不是傳回修改後的新清單
extend() ------------------- 在尾部一次性添加多個元素,需要将多個以清單形式傳入
insert的時間複雜度為O(n),少用
+、*不可本地修改
示例:
運作結果:
*的坑:
(1)清單中是"複雜類型"
解釋:
實際上記憶體中在list中存放的是指向清單[1,2,3]的位址,當複制的時候隻是把位址複制了一份,即淺拷貝,然後三個位址指向相同的記憶體,更改其中一個就會改變其他兩個
(2)清單中是“簡單類型”
不會改變其他的幾個元素
c.删除元素
del list[0] ---------------------------- 删除指定元素,删除後無法再通路
pop() ---------------------------- 删除末尾的元素,并且可以接受它的傳回值,也可以不接收,在括号中傳入索引時,就是删除指
定索引處的元素
remove(值) ------------------------------ 删除指定值第一次出現的位置的元素,如果要删除的值可能在清單中出現多次,就需要使用循環 來删除所有,使用remove可以接收它删除的值,也可以不接收
remove的時間複雜度為O(n),建議少用,能不用則不用
pop不傳入參數:從尾部彈出,時間複雜度為O(1)
pop傳出參數:從中間彈出,查找為O(1),但删除之後挪動元素為O(n),時間複雜度為O(n),不建議常從中間删除
clear會釋放大量垃圾記憶體,頻繁使用會使GC工作,使性能下降
示例:
運作結果:
d.元素排序
sort() ------------------------- 成員函數,本地修改,對原清單進行永久性修改排列順序,是按内置的規則排序,比如數字按照從小到大,
字母按照字典中字母順序,不能擷取傳回值,相當于C++中的引用修改
sorted() ---------------------- 全局函數,臨時修改,對原清單不改變,通過它的傳回值使用它
上述兩個函數都可以通過傳入參數reverse=True來進行反向排序
通過傳入key=某個函數來指定sort()内,比較的規則,然後按照相應規則排序後隻改變元素的位置,不改變元素原來的值
示例1:
示例2:
reverse() ---------------------- 成員函數,本地修改,對原清單進行修改,隻是按照元素的位置進行翻轉,不能擷取傳回值,
但可通過再次調用reserve(),少用
reversed()------------------------ 全局函數,臨時修改,對原清單不改變,通過它的傳回值使用它
示例:
運作結果:
操作清單
(1)擷取清單的長度-------len(list)
len是如何擷取list的長度的?
實際上list内部就維護着一個length的值,當調用len()的函數時,就查詢length的值,時間複雜度為O(1)
(2)對數字清單進行簡單的統計計算
min() -------------------求最小值
max() -------------------求最大值
sum() -------------------對清單中的數字求和
示例:
運作結果:
(3)清單解析——用一行生成代碼
變量名=[使用循環變量的式子 for 循環變量 in range()]
這裡的for循環不需要冒号
示例:
運作結果:
(4)周遊切片
可以使用切片來周遊清單中的部分元素
示例:
運作結果:
(5)複制清單
示例1:
運作結果1:
分析:
可以看出如果直接将一個清單賦給一個變量,其實隻是将該清單的位址賦給該變量,即引用類型的指派隻是位址的複制,修改新的變量會修改到原來的被複制變量,此為淺拷貝
示例2:
我們可以使用copy()函數或預設切片來進行複制,但是。。。觀察下面
運作結果2:
分析:
可以發現通過copy函數雖然對于最外層的清單進行了深拷貝,對于内層的引用類型還是進行了淺拷貝,隻是複制了位址
淺拷貝(shadow copy):遇到引用類型,隻是複制了一個引用而已
示例3:
深拷貝:複制的是對象的内容
python中的copy子產品提供了一個deepcopy方法
運作結果3:
總結:
(6)清單查詢
index和count會周遊整個序列,不建議常用