1. 列表
- 列表是Python中內置有序、可變序列,列表的所有元素放在一對中括號“[]”中,並使用逗號分隔開;
- 當列表元素增加或刪除時,列表對象自動進行擴展或收縮內存,保證元素之間沒有縫隙;
- 在Python中,一個列表中的數據類型可以各不相同,可以同時分別為整數、實數、字符串等基本類型,甚至是列表、元組、字典、集合以及其他自定義類型的對象。
[10, 20, 30, 40]
['crunchy frog', 'ram bladder', 'lark vomit']
['spam', 2.0, 5, [10, 20]]
[['file1', 200,7], ['file2', 260,9]] - 列表常用方法
方法 | 說明 |
lst.append(x) | 將元素x添加至列表lst尾部 |
lst.extend(L) | 將列表L中所有元素添加至列表lst尾部 |
lst.insert(index, x) | 在列表lst指定位置index處添加元素x,該位置后面的所有元素后移一個位置 |
lst.remove(x) | 在列表lst中刪除首次出現的指定元素,該元素之后的所有元素前移一個位置 |
lst.pop([index]) | 刪除並返回列表lst中下標為index(默認為-1)的元素 |
lst.clear() | 刪除列表lst中所有元素,但保留列表對象 |
lst.index(x) | 返回列表lst中第一個值為x的元素的下標,若不存在值為x的元素則拋出異常 |
lst.count(x) | 返回指定元素x在列表lst中的出現次數 |
lst.reverse() | 對列表lst所有元素進行逆序 |
lst.sort(key=None, reverse=False) | 對列表lst中的元素進行排序,key用來指定排序依據,reverse決定升序(False),還是降序(True) |
lst.copy() | 返回列表lst的淺復制 |
1.1 列表創建與刪除
-
使用“=”直接將一個列表賦值給變量即可創建列表對象
>>> a_list = ['a', 'b', 'mpilgrim', 'z', 'example']
>>> a_list = [] #創建空列表 -
也可以使用list()函數將元組、range對象、字符串或其他類型的可迭代對象類型的數據轉換為列表。
>>> a_list = list((3,5,7,9,11))
>>> a_list
[3, 5, 7, 9, 11]
>>> list(range(1,10,2))
[1, 3, 5, 7, 9]
>>> list('hello world')
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
>>> x = list() #創建空列表 -
當不再使用時,使用del命令刪除整個列表,如果列表對象所指向的值不再有其他對象指向,Python將同時刪除該值。
>>> del a_list
>>> a_list
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
a_list
NameError: name 'a_list' is not defined
1.2 列表元素的增加
-
可以使用“+”運算符將元素添加到列表中。
>>> aList = [3,4,5]
>>> aList = aList + [7]
>>> aList
[3, 4, 5, 7]
嚴格意義上來講,這並不是真的為列表添加元素,而是創建了一個新列表,並將原列表中的元素和新元素依次復制到新列表的內存空間。由於涉及大量元素的復制,該操作速度較慢,在涉及大量元素添加時不建議使用該方法。 -
使用列表對象的append()方法在當前列表尾部追加元素,原地修改列表,是真正意義上的在列表尾部添加元素,速度較快。
>>> aList.append(9)
>>> aList
[3, 4, 5, 7, 9]
所謂“原地”,是指不改變列表在內存中的首地址。 -
Python采用的是基於值的自動內存管理方式,當為對象修改值時,並不是真的直接修改變量的值,而是使變量指向新的值,這對於Python所有類型的變量都是一樣的。
>>> a = [1,2,3]
>>> id(a) #返回對象的內存地址
20230752
>>> a = [1,2]
>>> id(a)
20338208 -
列表中包含的是元素值的引用,而不是直接包含元素值。
如果是直接修改序列變量的值,則與Python普通變量的情況是一樣的
如果是通過下標來修改序列中元素的值或通過可變序列對象自身提供的方法來增加和刪除元素時,序列對象在內存中的起始地址是不變的,僅僅是被改變值的元素地址發生變化,也就是所謂的“原地操作”。
>>> a = [1,2,4]
>>> b = [1,2,3]
>>> a == b
False
>>> id(a) == id(b)
False
>>> id(a[0]) == id(b[0])
True
>>> a = [1,2,3]
>>> id(a)
25289752
>>> a.append(4)
>>> id(a)
25289752
>>> a.remove(3)
>>> a
[1, 2, 4]
>>> id(a)
25289752
>>> a[0] = 5
>>> a
[5, 2, 4]
>>> id(a)
25289752 -
使用列表對象的extend()方法可以將另一個迭代對象的所有元素添加至該列表對象尾部。通過extend()方法來增加列表元素也不改變其內存首地址,屬於原地操作。
>>> a.extend([7,8,9])
>>> a
[5, 2, 4, 7, 8, 9]
>>> id(a)
25289752
>>> aList.extend([11,13])
>>> aList
[3, 4, 5, 7, 9, 11, 13]
>>> aList.extend((15,17))
>>> aList
[3, 4, 5, 7, 9, 11, 13, 15, 17] -
使用列表對象的insert()方法將元素添加至列表的指定位置。
>>> aList.insert(3, 6) #在下標為3的位置插入元素6
>>> aList
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
應盡量從列表尾部進行元素的增加與刪除操作。
列表的insert()可以在列表的任意位置插入元素,但由於列表的自動內存管理功能,insert()方法會引起插入位置之后所有元素的移動,這會影響處理速度。
類似的還有后面介紹的remove()方法以及使用pop()函數彈出列表非尾部元素和使用del命令刪除列表非尾部元素的情況。
import timedef Insert():
a = []
for i in range(10000):
a.insert(0, i)def Append():
a = []
for i in range(10000):
a.append(i)start = time.time()
for i in range(10):
Insert()
print('Insert:', time.time()-start)start = time.time()
for i in range(10):
Append()
print('Append:', time.time()-start)
上面代碼運行結果如下:
Insert: 0.578000068665
Append: 0.0309998989105 -
使用乘法來擴展列表對象,將列表與整數相乘,生成一個新列表,新列表是原列表中元素的重復。
>>> aList = [3,5,7]
>>> bList = aList
>>> id(aList)
57091464
>>> id(bList)
57091464
>>> aList = aList*3
>>> aList
[3, 5, 7, 3, 5, 7, 3, 5, 7]
>>> bList
[3,5,7]
>>> id(aList)
57092680
>>> id(bList)
57091464
當使用*運算符將包含列表的列表重復並創建新列表時,並不是復制子列表值,而是復制已有元素的引用。因此,當修改其中一個值時,相應的引用也會被修改。
>>> x = [[None] * 2] * 3
>>> x
[[None, None], [None, None], [None, None]]
>>> x[0][0] = 5
>>> x
[[5, None], [5, None], [5, None]]
>>> x = [[1,2,3]] * 3
>>> x[0][0] = 10
>>> x
[[10, 2, 3], [10, 2, 3], [10, 2, 3]]
1.3 列表元素的刪除
-
使用del命令刪除列表中的指定位置上的元素。
>>> a_list = [3,5,7,9,11]
>>> del a_list[1]
>>> a_list
[3, 7, 9, 11] -
使用列表的pop()方法刪除並返回指定位置(默認為最后一個)上的元素,如果給定的索引超出了列表的范圍則拋出異常。
>>> a_list = list((3,5,7,9,11))
>>> a_list.pop()
11
>>> a_list
[3, 5, 7, 9]
>>> a_list.pop(1)
5
>>> a_list
[3, 7, 9] -
使用列表對象的remove()方法刪除首次出現的指定元素,如果列表中不存在要刪除的元素,則拋出異常。
>>> a_list = [3,5,7,9,7,11]
>>> a_list.remove(7)
>>> a_list
[3, 5, 9, 7, 11]
代碼編寫好后必須要經過反復測試,不能滿足於幾次測試結果正確。例如,下面的代碼成功地刪除了列表中的重復元素,執行結果是完全正確的。
>>> x = [1,2,1,2,1,2,1,2,1]
>>> for i in x:
if i == 1:
x.remove(i)
>>> x
[2, 2, 2, 2]
然而,上面這段代碼的邏輯是錯誤的。同樣的代碼,僅僅是所處理的數據發生了一點變化,然而當循環結束后卻發現並沒有把所有的“1”都刪除,只是刪除了一部分。
>>> x = [1,2,1,2,1,1,1]
>>> for i in x:
if i == 1:
x.remove(i)
>>> x
[2, 2, 1]
兩組數據的本質區別在於,第一組數據中沒有連續的“1”,而第二組數據中存在連續的“1”。出現這個問題的原因是列表的自動內存管理功能。
在刪除列表元素時,Python會自動對列表內存進行收縮並移動列表元素以保證所有元素之間沒有空隙,增加列表元素時也會自動擴展內存並對元素進行移動以保證元素之間沒有空隙。每當插入或刪除一個元素之后,該元素位置后面所有元素的索引就都改變了。
正確的代碼:
>>> x = [1,2,1,2,1,1,1]
>>> for i in x[::]: #切片
if i == 1:
x.remove(i)
或者:
>>> x = [1,2,1,2,1,1,1]
>>> for i in range(len(x)-1,-1,-1): #從后往前刪
if x[i]==1:
del x[i]
1.4 列表元素訪問與計數
-
使用下標直接訪問列表元素,如果指定下標不存在,則拋出異常。
>>> aList[3]
6
>>> aList[3] = 5.5
>>> aList
[3, 4, 5, 5.5, 7, 9, 11, 13, 15, 17]
>>> aList[15]
Traceback (most recent call last):
File "<pyshell#34>", line 1, in <module>
aList[15]
IndexError: list index out of range -
使用列表對象的index()方法獲取指定元素首次出現的下標,若列表對象中不存在指定元素,則拋出異常。
>>> aList
[3, 4, 5, 5.5, 7, 9, 11, 13, 15, 17]
>>> aList.index(7)
4
>>> aList.index(100)
Traceback (most recent call last):
File "<pyshell#36>", line 1, in <module>
aList.index(100)
ValueError: 100 is not in list -
使用列表對象的count()方法統計指定元素在列表對象中出現的次數。
>>> aList
[3, 4, 5, 5.5, 7, 9, 11, 13, 15, 17]
>>> aList.count(7)
1
>>> aList.count(0)
0
>>> aList.count(8)
0
1.5 成員資格判斷
-
使用in關鍵字來判斷一個值是否存在於列表中,返回結果為“True”或“False”。
>>> aList
[3, 4, 5, 5.5, 7, 9, 11, 13, 15, 17]
>>> 3 in aList
True
>>> 18 in aList
False
>>> bList = [[1], [2], [3]]
>>> 3 in bList
False
>>> 3 not in bList
True
>>> [3] in bList
True
>>> aList = [3, 5, 7, 9, 11]
>>> bList = ['a', 'b', 'c', 'd']
>>> (3, 'a') in zip(aList, bList)
True
>>> for a, b in zip(aList, bList):
print(a, b)
1.6 切片操作
-
切片適用於列表、元組、字符串、range對象等類型,但作用於列表時功能最強大。可以使用切片來截取列表中的任何部分,得到一個新列表,也可以通過切片來修改和刪除列表中部分元素,甚至可以通過切片操作為列表對象增加元素。
切片使用2個冒號分隔的3個數字來完成:
第一個數字表示切片開始位置(默認為0)。
第二個數字表示切片截止(但不包含)位置(默認為列表長度)。
第三個數字表示切片的步長(默認為1),當步長省略時可以順便省略最后一個冒號。
切片操作不會因為下標越界而拋出異常,而是簡單地在列表尾部截斷或者返回一個空列表,代碼具有更強的健壯性。 -
>>> aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> aList[::] #返回包含所有元素的新列表
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> aList[::-1] #逆序的所有元素
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
>>> aList[::2] #偶數位置,隔一個取一個
[3, 5, 7, 11, 15]
>>> aList[1::2] #奇數位置,隔一個取一個
[4, 6, 9, 13, 17]
>>> aList[3::] #從下標3開始的所有元素
[6, 7, 9, 11, 13, 15, 17]
>>> aList[3:6] #下標在[3, 6)之間的所有元素
[6, 7, 9]
>>> aList[0:100:1] #前100個元素,自動截斷
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> aList[100:] #下標100之后的所有元素,自動截斷
[]
>>> aList[100] #直接使用下標訪問會發生越界
IndexError: list index out of range -
可以使用切片來原地修改列表內容
>>> aList = [3, 5, 7]
>>> aList[len(aList):] = [9] #在尾部追加元素
>>> aList
[3, 5, 7, 9]
>>> aList[:3] = [1, 2, 3] #替換前3個元素
>>> aList
[1, 2, 3, 9]
>>> aList[:3] = [] #刪除前3個元素
>>> aList
[9]
>>> aList = list(range(10))
>>> aList
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> aList[::2] = [0]*5 #替換偶數位置上的元素
>>> aList
[0, 1, 0, 3, 0, 5, 0, 7, 0, 9]
>>> aList[::2] = [0]*3 #切片不連續,兩個元素個數必須一樣多
ValueError: attempt to assign sequence of size 3 to extended slice of size 5 -
使用del與切片結合來刪除列表元素
>>> aList = [3,5,7,9,11]
>>> del aList[:3] #刪除前3個元素
>>> aList
[9, 11]
>>> aList = [3,5,7,9,11]
>>> del aList[::2] #刪除偶數位置上的元素
>>> aList
[5, 9] -
切片返回的是列表元素的淺復制
>>> aList = [3, 5, 7]
>>> bList = aList #bList與aList指向同一個內存
>>> bList
[3, 5, 7]
>>> bList[1] = 8 #修改其中一個對象會影響另一個
>>> aList
[3, 8, 7]
>>> aList == bList #兩個列表的元素完全一樣
True
>>> aList is bList #兩個列表是同一個對象
True
>>> id(aList) #內存地址相同
19061816
>>> id(bList)
19061816 -
所謂淺復制,是指生成一個新的列表,並且把原列表中所有元素的引用都復制到新列表中。如果原列表中只包含整數、實數、復數等基本類型或元組、字符串這樣的不可變類型的數據,一般是沒有問題的。
>>> aList = [3, 5, 7]
>>> bList = aList[::] #切片,淺復制
>>> aList == bList #兩個列表的元素完全一樣
True
>>> aList is bList #但不是同一個對象
False
>>> id(aList) == id(bList) #內存地址不一樣
False
>>> bList[1] = 8 #修改其中一個不會影響另一個
>>> bList
[3, 8, 7]
>>> aList
[3, 5, 7] -
如果原列表中包含列表之類的可變數據類型,由於淺復制時只是把子列表的引用復制到新列表中,這樣的話修改任何一個都會影響另外一個。
>>> x = [1, 2, [3,4]]
>>> y = x[:]
>>> x[0] = 5
>>> x
[5, 2, [3, 4]]
>>> y
[1, 2, [3, 4]]
>>> x[2].append(6)
>>> x
[5, 2, [3, 4, 6]]
>>> y
[1, 2, [3, 4, 6]]
1.7 列表排序
-
使用列表對象的sort()方法進行原地排序,支持多種不同的排序方法。
>>> aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> import random
>>> random.shuffle(aList)
>>> aList
[3, 4, 15, 11, 9, 17, 13, 6, 7, 5]
>>> aList.sort() #默認是升序排序
>>> aList.sort(reverse = True) #降序排序
>>> aList
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
>>> aList.sort(key = lambda x:len(str(x))) #按轉換成字符串的長度排序
>>> aList
[9, 7, 6, 5, 4, 3, 17, 15, 13, 11] -
使用內置函數sorted()對列表進行排序並返回新列表
>>> aList
[9, 7, 6, 5, 4, 3, 17, 15, 13, 11]
>>> sorted(aList) #升序排序
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> sorted(aList,reverse = True) #降序排序
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3] -
使用列表對象的reverse()方法將元素原地逆序
>>> aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> aList.reverse()
>>> aList
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3] -
使用內置函數reversed()對列表元素進行逆序排列並返回迭代對象
>>> aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> newList = reversed(aList) #返回reversed對象
>>> list(newList) #把reversed對象轉換成列表
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
>>> for i in newList:
print(i, end=' ') #這里沒有輸出內容
#迭代對象已遍歷結束
>>> newList = reversed(aList) #重新創建reversed對象
>>> for i in newList:
print(i, end=' ')
17 15 13 11 9 7 6 5 4 3
1.8 用於序列操作的常用內置函數
-
len(列表):返回列表中的元素個數,同樣適用於元組、字典、集合、字符串等。
max(列表)、 min(列表):返回列表中的最大或最小元素,同樣適用於元組、字典、集合、range對象等。
sum(列表):對列表的元素進行求和運算,對非數值型列表運算需要指定start參數,同樣適用於元組、range。
>>> sum(range(1, 11)) #sum()函數的start參數默認為0
55
>>> sum(range(1, 11), 5) #指定start參數為5,等價於5+sum(range(1,11))
60
>>> sum([[1, 2], [3], [4]], []) #這個操作占用空間較大,慎用
[1, 2, 3, 4] -
zip()函數返回可迭代的zip對象。
>>> aList = [1, 2, 3]
>>> bList = [4, 5, 6]
>>> cList = zip(a, b) #返回zip對象
>>> cList
<zip object at 0x0000000003728908>
>>> list(cList) #把zip對象轉換成列表
[(1, 4), (2, 5), (3, 6)] -
enumerate(列表):枚舉列表元素,返回枚舉對象,其中每個元素為包含下標和值的元組。該函數對元組、字符串同樣有效。
>>> for item in enumerate('abcdef'):
print(item)(0, 'a')
(1, 'b')
(2, 'c')
(3, 'd')
(4, 'e')
(5, 'f')
1.9 列表推導式
-
列表推導式在內部實際上是一個循環結構,只是形式更加簡潔,例如:
>>> aList = [x*x for x in range(10)]
相當於
>>> aList = []
>>> for x in range(10):
aList.append(x*x)
也相當於
>>> aList = list(map(lambda x: x*x, range(10)))