申明: 本站飛宇網 https://feiyetopro.blogspot.com/。自網路收集整理之書籍、文章、影音僅供預覽交流學習研究,其[書籍、文章、影音]情節內容, 評論屬其個人行為, 與本網站無關。版權歸原作者和出版社所有,請在下載 24 小時內刪除,不得用作商業用途;如果您喜歡其作品,請支持訂閱購買[正版]。謝謝!

資料結構是用來存儲資料的邏輯結構,合理使用資料結構才能編寫出優秀的代碼。本章將向讀者介紹Python提供的幾種內置資料結構——元組、清單、字典和序列。內置資料結構是Python語言的精華,也是使用Python進行開發的基礎。
本章的知識點:
·元組、清單和字典的創建和使用
·元組的遍歷
·元組和列表的“解包”操作
·列表的排序、查找和反轉
·字典特性
·序列的含義
4.1 元組結構
元組是Python中常用的一種資料結構。元組由不同的元素組成,每個元素可以存儲不同類型的資料,如字串、數位甚至元組。元組是“防寫”的,即元組創建後不能再做任何修改操作,元組通常代表一行資料,而元組中的元素代表不同的資料項目。
4.1.1 元組的創建
Tuple(元組)是Python內置的一種資料結構。元組由一系列元素組成,所有元素被包含在一對圓括號中。創建元組時,可以不指定元素的個數,相當於不定長的陣列,但是一旦創建後就不能修改元組的長度。元組創建的格式如下所示。
tuple = (元素1, 元素2, …)
元組的初始化示例如下:
tuple = ("apple",
"banana", "grape", "orange")
上面這行代碼創建了一個名為tuple的元組,該元組由4個元素組成,元素之間使用逗號分隔。
如果需要定義一個空的元組,表達方式更簡單。創建空的元組只需要一對空的圓括號。
tuple = ()
如果創建的元組只包含一個元素,通常會錯誤地忽略單元素後的逗號。Python無法區分變數tuple是元組還是運算式,Python誤認為圓括號中的內容為運算式,因此tuple[0]輸出的結果並非期望的值,並且其類型也不是tuple。錯誤的寫法如下:
01
tuple = ("apple")
# 定義元組
02
print(tuple[0]) # 列印第一個元素
03 print (type(tuple)) # 列印定義的tuple的類型
運行這段代碼並不會提示任何錯誤,代碼將輸出字母“a”,而不是期望的“apple”。並且其類型為<class‘str’>。正確的寫法如下:
01
tuple = ("apple",)
# 定義元組,注意後面的逗號不可少
02
print (tuple[0]) # 列印第一個元素
03
print (type(tuple)) # 列印定義的tuple的類型
此時,將輸出tuple元組中唯一的元素“apple”,並且類型為<class‘tuple’>。所以,創建一個唯一元素的元組,需要在元素的後面添加一個逗號,使Python能正確識別出元組中的元素。
注意 元組是從0開始計數的,因此tuple[0]獲得的是元組tuple中第1個元素。Python中其他的資料結構也遵循這個規則。
4.1.2 元組的訪問
元組中元素的值通過索引訪問,索引是一對方括弧中的數位,索引也稱為“下標”。元組的訪問格式如下。
tuple[n]
其中,tuple[n]表示訪問元組的第n個元素,索引n的值可以為0、正整數或負整數。前面一節已經提到了元組的輸出方法,例如:
print (tuple[1])
上面這行代碼將輸出字串“banana”,print語句表示輸出,tuple[1]表示訪問tuple的第2個元素。
可以把元組理解為陣列,使用C或Java語言程式設計的讀者應該不會陌生,陣列的下標是從0開始計數,而元組中元素的訪問也符合這個規則。
元組創建後其內部元素的值不能被修改,如果修改元組中的某個元素,運行時將報錯。例如:
tuple[0] = "a"
對tuple元組中第1個元素進行賦值,運行代碼後錯誤資訊如下:
TypeError: 'tuple' object does not
support item assignment
可見,元組中的元素並不支援賦值操作。
注意 元組不能添加或刪除任何元素。因此,元組不存在任何添加、刪除元素的方法,元組也不存在任何其他方法。
元組的訪問還有一些特殊的用法,這些用法對於獲取元組的值非常方便,例如負數索引和分片索引。這兩個特性是Python的特殊用法,C或Java語言並不支援。負數索引從元組的尾部開始計數,最尾端的元素索引表示“-1”,次尾端的元素索引表示“-2”,依次類推。圖4-1演示了負數索引與元素的對應關係,tuple[-1]的值為value4,tuple[-2]的值為value3。
分片(slice)是元組的一個子集,分片是從第1個索引到第2個索引(不包含第2個索引所指向的元素)所指定的所有元素。分片索引可以為正數或負數,兩個索引之間用冒號分隔。分片的格式如下所示:
tuple[m:n]
其中,m、n可以是0、正整數或負整數。
圖4-2演示了分片索引與元素的對應關係,tuple[1:3]將返回(value2,value3,value4)。


下面這段代碼將說明負數索引和分片索引的使用。
01
tuple = ("apple", "banana", "grape",
"orange") # 定義元組
02
print (tuple[-1])
03
print (tuple[-2])
04
tuple2 = tuple[1:3]
# 分片,第二個元素到第三個元素(不包括第四個)
05
tuple3 = tuple[0:-2]
# 分片,從第一個元素到倒數第二個元素(不包括倒數第二個)
06
tuple4 = tuple[2:-2]
# 分片,從第三個元素到倒數第二個元素(不包括倒數第二個)
07
print (tuple2)
08
print (tuple3)
09
print (tuple4)
【代碼說明】
·元組的索引可以用負數表示,第2、3行代碼將分別輸出“orange”和“apple”。
·使用分片截取後,將得到一個新的元組。第4行到第6行代碼分別創建了3個元組。
·tuple2輸出結果:('banana','grape')
·tuple3輸出結果:('apple','banana')
·tuple4輸出結果:('grape')
元組還可以由其他元組組成。例如,二元元組可以表示為:
tuple = (('t1', 't2'), ('t3', 't4'))
tuple是一個二元元組,該元組由('t1','t2')和('t3','t4')組成。
下面的代碼說明了元組間的包含關係以及元組中元素的訪問。
01
fruit1 = ("apple", "banana")
02
fruit2 = ("grape", "orange")
03
tuple = (fruit1, fruit2)
04
print (tuple)
05
print ("tuple[0][1] =", tuple[0][1])
06
print ("tuple[1][1] =", tuple[1][1])
07
print ("tuple[1][1] =", tuple[1][2])
【代碼說明】
·第3行代碼創建了一個複合元組tuple,tuple由元組fruit1和fruit2組成。元組tuple的輸出結果:
(('apple', 'banana'), ('grape',
'orange'))
·tuple[0][1]表示訪問tuple元組中第1個元組的第2個元素,即fruit1元組中的第2個元素,可以把tuple理解為二維陣列。tuple[0][1]輸出結果:
tuple[0][1] = banana
·tuple[1][1]表示訪問tuple元組中第2個元組的第2個元素,即fruit2元組中的第2個元素。tuple[1][1]輸出結果:
tuple[1][1] = orange
·同理,tuple[1][2]將訪問fruit2元組中的第3個元素,因為此元素不存在,元組的索引訪問越界。運行後將輸出如下錯誤資訊:
IndexError: tuple index out of range
tuple元組的存儲結構如圖4-3所示。
創建元組的過程,Python稱為“打包”。相反,元組也可以執行“解包”的操作。“解包”可以將包元組中的各個元素分別賦值給多個變數。這樣,避免了使用迴圈遍歷的方法獲取每個元素的值,降低了代碼的複雜性,使表達方式更自然。下面這個例子說明了元組“打包”和“解包”的過程。
01
#打包
02
tuple = ("apple", "banana", "grape",
"orange")
03
#解包
04
a, b, c, d = tuple
05
print (a, b, c, d)
【代碼說明】
·第2行代碼創建了一個tuple元組,元組的創建即“打包”的過程。
·第4行代碼使用了一個賦值操作,等號的右邊是tuple元組,等號的左邊有4個變數,元組tuple中的4個元素分別賦值給這4個變數。
·第5行代碼輸出4個變數的值,輸出的結果如下:
apple banana grape orange
4.1.3 元組的遍歷
元組的遍歷是指通過迴圈語句依次訪問元組中各元素的值。遍歷元組需要用到兩個函數range()和len()。range()和len()都是Python的內建函數,這些函數可直接調用,不需要import語句導入模組。內建函數是Python自動導入的函數,相當於Java中的lang包。
len()計算出tuple元組中元素的個數,range()返回一個由數字組成的清單,關於列表的概念請參考4.2節。range()的聲明如下所示。
range([start,] stop[, step]) -> list
of integers
【代碼說明】
·range()返回一個遞增或遞減的數位清單,清單的元素值由3個參數決定。
·參數start表示列表開始的值,預設值為0。
·參數stop表示列表結束的值,該參數不可缺少。
·參數step表示步長,每次遞增或遞減的值,預設值為1。
例如,range(5)返回的列表為[0,1,2,3,4]。下面這段代碼實現了二元元組的遍歷。
01
tuple = (("apple", "banana"),("grape",
"orange"),("watermelon",),("grapefruit",))
02
for i in range(len(tuple)):
03 print ("tuple[%d] :" % i,
"" ,)
04 for j in range(len(tuple[i])):
05 print (tuple[i][j], ""
,)
06 print()
【代碼說明】
·第1行代碼創建了一個由4個子元組組成的二元元組tuple。
·第2行到第6行代碼遍歷tuple元組,輸出元組中各個元素的值。tuple元組的遍歷結果:
tuple[0] : apple
banana
tuple[1] : grape
orange
tuple[2] : watermelon
tuple[3] : grapefruit
此外,也可以直接使用for…in語句遍歷元組,代碼如下:
01
tuple = (("apple", "banana"),("grape",
"orange"),("watermelon",),("grapefruit",))
02
for i in tuple: # 遍歷元組tuple
03 for j in i: # 同樣對子元組進行遍歷
04 print(j) # 依次列印出元素
【代碼說明】
·第1行同樣創建了一個元組。
·第2行開始遍歷元組tuple。
·第3行開始對各子元組進行遍歷。
·第4行列印出元素。
遍歷結果:
apple
banana
grape
orange
watermelon
grapefruit
4.2 清單結構
列表是Python中非常重要的資料類型,通常作為函數的返回類型。清單和元組相似,也是由一組元素組成,清單可以實現添加、刪除和查找操作,元素的值可以被修改。
4.2.1 列表的創建
List(清單)是Python內置的一種資料結構。它由一系列元素組成,所有元素被包含在一對方括弧中。列表創建後,可以執行添加或刪除操作。使用過Java語言的讀者可能想到了Java語言中的List介面,其中ArrayList類繼承自List介面,實現了動態陣列的功能,可以添加或刪除任意類型的物件。Python中列表的作用和ArrayList類相似,用法更靈活。列表創建的格式如下所示。
list = [元素1, 元素2, …]
列表的添加可以調用append(),該方法的聲明如下所示。
append(object)
其中,object可以是元組、清單、字典或任何物件。
列表的刪除可以調用remove(),該方法的聲明如下所示。
remove(value)
該方法將刪除元素value。如果value不在列表中,Python將拋出ValueError異常。下面這段代碼演示了清單的創建、添加和刪除。
01
list = ["apple", "banana", "grape",
"orange"] # 定義列表
02
print (list)
03
print (list[2])
04
list.append("watermelon") # 在清單末尾添加元素
05
list.insert(1, "grapefruit") # 向清單中插入元素
06
print (list)
07
list.remove("grape") # 從列表中移除grape
08
print (list)
09
list.remove("a") # 從列表中移除a,因為當前列表中並沒有a,所以將拋出錯誤
10
print (list.pop())
# 列印從清單中彈出的元素,即最後一個元素
11
print (list)
【代碼說明】
·第1行代碼創建了一個list列表,該清單由4個元素的組成。
·第2行代碼輸出list清單中的內容:
['apple', 'banana', 'grape', 'orange']
·第3行代碼輸出list清單中的第3個元素grape。
·第4行代碼調用list的append(),append()追加了一個“watermelon”元素到清單的末尾。
·第5行代碼調用insert(),insert()將元素插入指定的索引位置。這裡將“grapefruit”插入list的第2個位置。此時的list列表如下:
['apple', 'grapefruit', 'banana',
'grape', 'orange', 'watermelon']
·第7行代碼調用了remove(),移除“grape”元素,移除後的list列表如下:
['apple', 'grapefruit', 'banana',
'orange', 'watermelon']
·第9行代碼移除“a”元素,由於清單中不存在此元素,因此程式運行後提示如下錯誤:
ValueError: list.remove(x): x not in
list
·第10行代碼調用了pop(),pop()取出清單中最後一個元素,即“彈出”最後一個進入清單的元素“watermelon”。此時的list列表如下:
['apple', 'grapefruit', 'banana',
'orange']
注意 如果list列表中存在兩個相同的元素,此時調用remove()移除同名元素,將只刪除list清單中靠前的元素。例如,如果list中存在兩個“grape”元素,執行語句list.remove("grape")後,其中一個“grape”將被刪除,而且此元素是首次出現的那個“grape”元素。
4.2.2 列表的使用
列表的使用與元組十分相似,同樣支援負數索引、分片以及多元列表等特性,但是清單中的元素可修改,而且存在一些處理列表的方法。下面的代碼說明了負數索引和分片的使用以及二元列表的遍歷。
01
list = ["apple", "banana", "grape",
"orange"]
02
print (list[-2])
03
print (list[1:3])
04
print (list[-3:-1])
05
list = [["apple", "banana"],["grape",
"orange"],["watermelon"],["grapefruit"]]
06
for i in range(len(list)):
# 遍歷列表
07 print ("list[%d] :" % i,
"" ,)
08 for j in range(len(list[i])):
09
print (list[i][j],
"" ,)
10 print()
【代碼說明】
·第2行代碼輸出結果:
grape
·第3行代碼輸出結果:
['banana', 'grape']
·第4行代碼輸出結果:
['banana', 'grape']
·第6行到第10行代碼遍歷二元列表,輸出list清單中各元素的值。list列表中,各子列表的長度並不相同,這並不妨礙list列表的遍歷。list列表的輸出結果如下:
list[0] : apple
banana
list[1] : grape
orange
list[2] : watermelon
list[3] : grapefruit
列表實現了連接操作的功能,列表的連接同樣提供了兩種方式,一種是調用extend()連接兩個不同的列表,另一種是使用運算子“+”或“+=”。下面這段代碼演示了清單的連接功能。
01
list1 = ["apple", "banana"]
02
list2 = ["grape", "orange"]
03
list1.extend(list2) #
list1連接list2
04
print (list1)
05
list3 = ["watermelon"]
06
list1 = list1 + list3 # 將list1與list3連接後賦給list1
07
print (list1)
08
list1 += ["grapefruit"]
# 使用+=給list1連接上[“grapefruit”]
09
print (list1)
10
list1 = ["apple", "banana"] * 2
11
print (list1)
【代碼說明】
·第3行代碼調用extend(),輸出結果:
['apple', 'banana', 'grape', 'orange']
·第6行代碼使用“+”運算子連接兩個列表,輸出結果:
['apple', 'banana', 'grape', 'orange',
'watermelon']
·第8行代碼使用“+=”運算子,輸出結果:
['apple', 'banana', 'grape', 'orange',
'watermelon', 'grapefruit']
·第10行代碼使用“*”運算子,連接了兩個相同的['apple','banana']元組,輸出結果:
['apple', 'banana', 'apple', 'banana']
4.2.3 列表的查找、排序、反轉
前面已經提到,list列表可以進行添加、刪除操作,此外list清單還提供了查找元素的方法。List清單的查找提供了兩種方式,一種是使用index方法返回元素在清單中的位置,另一種方法是使用關鍵字“in”來判斷元素是否在清單中。下面這段代碼演示了清單的查找。
01
list = ["apple", "banana", "grape",
"orange"]
02
print (list.index("grape")) # 列印grape的索引
03
print (list.index("orange")) # 列印orange的索引
04 print ("orange" in list) # 判斷orange是否在列表中
【代碼說明】
·第2行代碼返回元素“grape”對應的索引值,輸出值為2。
·同理,第3行代碼的輸出值為3。
·第4行代碼判斷元素“orange”是否在list列表中,返回值為True。
列表提供了排序和反轉的方法,下面這段代碼展示了列表的排序和反轉。
01
list = ["banana", "apple", "orange",
"grape"]
02
list.sort() # 排序
03
print ("Sorted list:", list)
04
list.reverse()
# 反轉
05
print ("Reversed list:", list)
【代碼說明】
·第2行代碼調用sort(),元素按照首字母昇冪排序。排序後的結果:
Sorted list: ['apple', 'banana',
'grape', 'orange']
·第4行代碼調用reverse(),反轉清單中元素的排列順序。反轉後的結果:
Reversed list: ['orange', 'grape',
'banana', 'apple']
注意 在Python中,列表是由類list實現的。使用函數help(list)查看list類的定義,可以快速瞭解列表所包含的方法。Help函數同樣適用於其他Python類。
表4-1列出了列表的常用方法。
表4-1 列表的常用方法
4.2.4 清單實現堆疊和佇列
堆疊和佇列是資料結構中常用的資料結構,清單可以用來實現堆疊和佇列。
堆疊是指最先進入堆疊的元素最後才輸出,符合“後進先出”的順序。棧的插入、彈出是通過棧首指標控制的。插入一個新的元素,指標移到新元素的位置;彈出一個元素,指標移到下面一個元素的位置,即原堆疊倒數第2個元素的位置,該元素成為棧頂元素。
佇列是指最先進入佇列的元素最先輸出,符合“先進先出”的順序。佇列的插入、彈出是分別通過隊首指標和隊尾指標控制的。插入一個新的元素,隊尾指標移到新元素的位置;彈出一個元素,隊首指標移到原佇列中第2個元素的位置,該元素成為佇列的第1個元素。
使用列表的append()、pop()方法可以類比這兩個資料結構,append()、pop()的使用參見4.2.1小節。
首先分析一下堆疊的實現,調用append()可以把一個元素添加到堆疊的頂部,調用pop()方法把堆疊中最後一個元素彈出來。
假設有一個堆疊["apple","grape","grape"],要向堆疊中添加一個新的元素“orange”。圖4-4描述了清單實現堆疊的原理。
“apple”是列表中第1個進入的元素,所以置於堆疊的最底端。調用append("orange")後,程式把“orange”元素插到堆疊的頂部。此時棧的指標移動到元素“orange”,棧中包含4個元素,“orange”置於堆疊的頂部。然後調用pop(),彈出頂部的元素“orange”,棧的指針移到“grape”。
下面這段代碼使用清單類比了堆疊。
01
# 堆疊的實現
02
list = ["apple", "grape", "grape"]
03
list.append("orange") # 將orange壓入堆疊
04
print (list)
05
print ("彈出的元素:", list.pop()) # 從堆疊中彈出最後壓入的元素
06
print (list)
【代碼說明】
·第2行代碼創建了一個堆疊list。
·第3行代碼向堆疊中添加一個元素“orange”。
·第4行代碼輸出添加新元素後堆疊中的內容。輸出結果:
['apple', 'banana', 'grape', 'orange']
·第5行代碼彈出堆疊中最頂部的元素。輸出結果:彈出的元素:
orange
·第6行代碼輸出頂部元素被彈出後堆疊中的內容。輸出結果:
['apple', 'banana', 'grape']
佇列也是通過調用append()和pop()方法實現的。pop()的調用方式有所不同,通過調用pop(0)彈出佇列最前面的元素。假設有一個佇列["apple","grape","grape"],要向佇列中添加一個新的元素“orange”。圖4-5描述了清單實現佇列的原理。
“apple”是列表中第1個進入的元素,所以置於佇列的最前端。調用append("orange")後,程式把“orange”元素插到佇列的尾部,隊尾指標移到元素“orange”。此時清單中包含4個元素,“orange”置於佇列的尾部。然後調用pop(0),彈出佇列最前面的元素“apple”,隊首指標移到元素“banan”。從而實現了“先進先出”的佇列結構。下面這段代碼使用清單類比了佇列。
01
#佇列的實現
02
list = ["apple", "grape", "grape"]
03
list.append("orange") # 隊尾加入orange
04
print (list)
05
print ("彈出的元素:", list.pop(0)) # 彈出第一個元素
06
print (list)
【代碼說明】
·第2行代碼創建了一個佇列list。
·第3行代碼向佇列中添加一個元素“orange”。
·第4行代碼輸出添加新元素後佇列中的內容。輸出結果:
['apple', 'banana', 'grape', 'orange']
·第5行代碼彈出佇列最前面的元素。輸出結果:
彈出的元素: apple
·第6行代碼輸出最前面的元素被彈出後佇列中的內容。輸出結果:
['banana', 'grape', 'orange']
堆疊和佇列是資料結構這門課程探討的內容,讀者可以參考相關的書籍進一步學習。
4.3 字典結構
字典是Python中重要的資料類型,字典是由“鍵-值”對組成的集合,字典中的“值”通過“鍵”來引用。本節將介紹字典的定義、訪問、排序等功能。
4.3.1 字典的創建
字典由一系列的“鍵-值”(key-value)對組成,“鍵-值”對之間用“逗號”隔開,並且被包含在一對花括弧中。字典與Java語言中的HashMap類作用類似,都是採用“鍵-值”對映射的方式存儲資料。例如,在開發內容管理系統時,通常把欄目編號作為“鍵”、欄目名稱作為“值”存儲在字典結構中,通過欄目編號引用欄目名稱。
字典的創建和使用非常簡單,創建字典的格式如下所示:
dictionary = {key1 : value1, key2 :
value2, …}
其中,key1、key2等表示字典的key值,value1、value2等表示字典的value值。
如果需要創建一個空的字典,只需要一對花括弧即可,代碼如下所示:
dictionary = {}
下麵的代碼演示了字典的創建和訪問。
01
dict = {"a" : "apple", "b" :
"banana", "g" : "grape", "o" :
"orange"}
02
print (dict)
03
print (dict["a"])
# 列印鍵a對應的值
【代碼說明】
·第1行代碼創建字典dict,使用字母引用對應的值。
·第2行代碼輸出字典的結果:
{'a': 'apple', 'b': 'banana', 'o':
'orange', 'g': 'grape'}
·第3行代碼通過索引“a”獲取對應的值“apple”,輸出的結果:
apple
注意 字典的“鍵”是區分大小寫的。例如,dict["a"]與dict["A"]分別指向不同的值,應區別對待。
創建字典時,可以使用數位元作為索引。
dict = {1 : "apple", 2 :
"banana", 3 : "grape", 4 : "orange"}
print (dict)
print (dict[2])
【代碼說明】
·第1行代碼創建字典dict,這裡使用數位引用對應的值。
·字典dict輸出的結果:
{1: 'apple', 2: 'banana', 3: 'grape', 4:
'orange'}
·第3行代碼通過索引2獲取對應的值“banana”,輸出的結果:
banana
前面多次使用了print函數輸出結果,print()的使用非常靈活,也可以在print()中使用字典。下面這行代碼演示了字典在print()中的使用。
print ("%s, %(a)s, %(b)s" %
{"a":"apple", "b":"banana"})
【代碼說明】 其中隱式地創建了字典{"a":"apple","b":"banana"}。這個字典用來定制print()中的參數列表。“%s”輸出這個字典的內容,“%(a)s”獲取字典中對應key值“a”的value值,“%(b)s”獲取字典中對應key值“b”的value值。輸出結果:
{'a': 'apple', 'b': 'banana'}, apple,
banana
4.3.2 字典的訪問
字典的訪問與元組、列表有所不同,元組和清單是通過數位元索引來獲取對應的值,而字典是通過key值獲取相應的value值。訪問字典元素的格式如下所示。
value = dict[key]
字典的添加、刪除和修改非常簡單,添加或修改操作只需要編寫一條設定陳述式,例如:
dict["x"] = "value"
如果索引x不在字典dict的key清單中,字典dict將添加一條新的映射(x:value);如果索引x在字典dict的key清單中,字典dict將直接修改索引x對應的value值。
字典與清單不同,字典並沒有remove()操作。字典元素的刪除可以調用del()實現,del()屬於內建函數,直接調用即可。清單可以調用pop()彈出清單中一個元素,字典也有一個pop(),該方法的聲明和作用與列表的pop()有些不同。pop()的聲明如下所示。
D.pop(k[,d]) -> v
pop()必須指定參數才能刪除對應的值。其中,參數k表示字典的索引,如果字典D中存在索引k,返回值v等於D[k];如果字典D中沒有找到索引k,返回值為d。
如果需要清除字典中所有的內容,可以調用字典的clear()。下面這段代碼演示了這些常用的操作。
01
#字典的添加、刪除、修改操作
02
dict = {"a" : "apple", "b" :
"banana", "g" : "grape", "o" :
"orange"}
03
dict["w"] = "watermelon"
04
del(dict["a"]) # 刪除字典中鍵為a 的元素
05
dict["g"] = "grapefruit" # 修改字典中鍵為g的值
06
print (dict.pop("b")) # 彈出字典中鍵為b的元素
07
print (dict)
08
dict.clear() # 清除字典中所有元素
09
print (dict)
【代碼說明】
·第2行代碼創建字典dict,這裡使用字母引用對應的值。
·字典dict輸出的結果:{'e':'apple','b':'banana','g':'grape','o':'orange'}
由於字典是無序的,因此字典中沒有append()、remove()等方法。如果需要向字典插入新的元素,可以調用setdefault()。這個方法的使用將在4.3.3小節介紹。
字典的遍歷有多種方式,最直接的方式是通過“for…in…”語句完成遍歷的任務。下麵這段代碼演示了字典的遍歷操作。
01
#字典的遍歷
02
dict = {"a" : "apple", "b" :
"banana", "g" : "grape", "o" :
"orange"}
03
for k in dict:
04 print ("dict[%s] =" %
k,dict[k])
【代碼說明】
·第3行代碼使用了“for…in…”語句迴圈訪問字典dict。值得注意的是變數k獲取的是字典dict的key值,並沒有直接獲取value值。因此列印輸出時,通過dict[k]來獲取value值。
·第4行代碼依次輸出的結果:
dict[a] = apple
dict[b] = banana
dict[o] = orange
dict[g] = grape
此外,還可以使用字典的items()實現字典的遍歷操作,items()返回一個由若干元組組成的列表。下面這段代碼演示了items()的使用。
01
#字典items()的使用
02
dict = {"a" : "apple", "b" :
"banana", "c" : "grape", "d" :
"orange"}
03
print (dict.items())
【代碼說明】 本段程式將輸出以下結果。
[('a', 'apple'), ('c', 'grape'), ('b',
'banana'), ('d', 'orange')]
可見,items()把字典中每對key和value組成了一個元組,並把這些元組存放在列表中返回。下面將使用字典items()實現字典的遍歷。
01
#調用items()實現字典的遍歷
02
dict = {"a" : "apple", "b" :
"banana", "g" : "grape", "o" :
"orange"}
03
for (k, v) in dict.items():
04 print ("dict[%s] =" % k, v)
【代碼說明】 第3行代碼中的變數k和v分別與字典dict中的key和value值對應,遍歷輸出的結果如下。
dict[a] = apple
dict[b] = banana
dict[o] = orange
dict[g] = grape
前面的代碼都採用字串作為字典的value值,元組、清單甚至字典都可以作為字典的value值。使用元組、清單或字典作為value值創建的字典,稱為混合型字典。下面將說明如何訪問混合型字典的內容。
混合型字典的創建格式如下所示。
dict =
{"key1" : (tuple), "key2" : [list], "key3"
: [dictionary] …}
下麵這段代碼演示了混合型字典的創建和訪問。
01
#使用清單、字典作為字典的值
02
dict = {"a" : ("apple",), "bo" :
{"b" : "banana", "o" : "orange"},
"g" : ["grape","grapefruit"]}
03
print (dict["a"])
04
print (dict["a"][0])
05
print (dict["bo"])
06
print (dict["bo"]["o"])
07
print (dict["g"])
08
print (dict["g"][1])
【代碼說明】
·第2行代碼創建了一個包含元組、清單和字典的混合型字典。
·第3行代碼返回嵌套的元組,輸出結果:('apple',)
·第4行代碼使用了雙下標訪問元組的第1個元素,輸出結果:apple
·第5行代碼返回嵌套的字典,輸出結果:{'b':'banana','o':'orange'}
·第6行代碼使用雙下標訪問嵌套字典中key值“o”對應的value值,輸出結果:orange
·第7行代碼返回嵌套的列表,輸出結果:['grape','grapefruit']
·第8行代碼返回嵌套清單中的第2個元素的值,輸出結果:grapefruit
4.3.3 字典的方法
前面已經使用了一些字典的方法,本節將詳細介紹字典的常用方法,使用這些常用方法可以極大地提高程式設計效率。keys()和values()分別返回字典的key清單和value列表。下面這段代碼演示了keys()和values()的使用。
01
dict = {"a" : "apple", "b" :
"banana", "c" : "grape", "d" :
"orange"}
02
#輸出key的列表
03
print (dict.keys())
04
#輸出value的列表
05
print (dict.values())
【代碼說明】
·第3行代碼返回由字典的key值組成的列表,輸出結果:
['a', 'c', 'b', 'd']
·第5行代碼返回由字典的value值組成的列表,輸出結果:
['apple', 'grape', 'banana', 'orange']
前面已經提到,要獲取字典中某個value值,可以使用dict[key]的結構訪問。另一種獲取value值的辦法是使用字典的get(),get()的聲明如下:
D.get(k[,d]) -> D[k]
【代碼說明】
·參數k表示字典的鍵值,參數d可以作為get()的返回值,參數d可以默認,預設值為None。
·get()相當於一條if…else…語句,如果參數k在字典D中,get()將返回D[k];如果參數k不在字典D中,則返回參數d。get()的等價語句如下所示:
01
#get()的等價語句
02
D = {"key1" : "value1", "key2" :
"value2"}
03
if "key1" in D:
04 print (D["key1"])
05
else:
06 print ("None")
【代碼說明】 由於在字典D中查找到了key值“key1”,所以輸出結果為“value1”。
下面的代碼演示了get()的使用。
01
#字典中元素的獲取方法
02
dict = {"a" : "apple", "b" :
"banana", "c" : "grape", "d" :
"orange"}
03
print (dict)
04
print (dict.get("c", "apple")) # 使用get獲取鍵為c的值,若不存在返回預設值apple
05
print (dict.get("e", "apple")) # 使用get獲取鍵為e的值,若不存在返回預設值apple
【代碼說明】
·第4行代碼由於字典dict存在索引“c”,所以返回key值“c”對應的value值。輸出結果:
grape
·第5行代碼由於字典dict中不存在索引“e”,所以返回預設值“apple”。輸出結果:
apple
採用get()訪問字典中的value值減少了代碼的長度,而且表達方式容易理解,避免了使用if語句帶來的維護代價。
如果需要添加新的元素到已經存在的字典中,可以調用字典的update()。update()把一個字典中的key和value值全部複製到另一個字典中,update()相當於一個合併函數。update()的聲明如下所示:
D.update(E) -> None
把字典E的內容合併到字典D中,update()的等價代碼如下所示:
01
#udpate()的等價語句
02
D = {"key1" : "value1", "key2" :
"value2"}
03
E = {"key3" : "value3", "key4" :
"value4"}
04
for k in E:
05 D[k] = E[k]
06
print (D)
【代碼說明】 第4行代碼通過for…in…迴圈語句訪問字典E,並把字典E中的內容逐個添加到字典D中。字典D更新後的結果:
{'key3': 'value3', 'key2': 'value2',
'key1': 'value1', 'key4': 'value4'}
如果字典E中含有與字典D中相同的鍵值,字典E的值將覆蓋字典D中的值。例如:
01
#字典E中含有字典D中的key
02
D = {"key1" : "value1", "key2" :
"value2"}
03
E = {"key2" : "value3", "key4" :
"value4"}
04
for k in E:
05
D[k] = E[k]
06
print (D)
【代碼說明】 字典D和字典E都含有一個名為“key2”的鍵,但是對應的value值並不相同。字典D更新後的結果:
{'key2': 'value3', 'key1': 'value1',
'key4': 'value4'}
字典的update()也存在同樣的問題,如果某些key在目標字典中已經存在,則更新後新字典中的值將覆蓋原有的值。下面的代碼演示了update()的使用。
01
#字典的更新
02
dict = {"a" : "apple", "b" :
"banana"}
03
print (dict)
04
dict2 = {"c" : "grape", "d" :
"orange"}
05
dict.update(dict2) # 使用update方法更新dict
06
print (dict)
【代碼說明】 第5行代碼調用update(),把字典dict2的內容更新到字典dict,字典dict原有的內容保持不變。字典dict的輸出結果:
{'a': 'apple', 'c': 'grape', 'b':
'banana', 'd': 'orange'}
注意 字典不屬於序列,所以字典沒有順序性。update()調用後,字典中各元素的排列順序是無序。關於序列的概念將在4.4節介紹。
字典的setdefault()可以創建新的元素並設置預設值。setdefault()的聲明如下所示。
D.setdefault(k[,d]) -> D.get(k,d)
【代碼說明】 setdefault()與get()的使用有些相似,參數k表示字典的鍵值,參數d表示D[k]的預設值。參數d可以省略,預設值為None。如果參數k的值在字典D中,setdefault()將返回get(k,d)獲得的結果;如果參數k的值不在字典D中,字典D將添加新的元素D[k],並調用get(k,d)返回參數d的值。
下面的代碼演示了setdefault()的使用。
01
# 設置預設值
02
dict = {}
03
dict.setdefault("a")
04
print (dict)
05
dict["a"] = "apple"
06
dict.setdefault("a", "None")
07
print (dict)
【代碼說明】
·第3行代碼添加了一個key值為“a”,且設置默認value值為None。Setdefault("a")的返回值結果為None。
·第4行代碼輸出結果:{'a':None}
·第5行代碼更新dict["a"]的值為“apple”。
·第6行代碼再次調用setdefault(),設置默認的value值為None。
·第7行代碼輸出字典dict的內容,由於設置了dict["a"]的值為“apple”,即使再次調用setdefault()也不會影響value值,所以dict["a"]的值仍為“apple”,而非“default”。字典dict的輸出結果:
{'a': 'apple'}
表4-2列出了字典中常用的一些方法。
表4-2 字典的常用方法

4.3.4 字典的排序、複製
前面已經提到,列表的排序可以使用sorted()實現,字典的排序同樣可以使用該函數。下面的代碼演示了使用sorted()實現字典的排序。
01
#調用sorted()排序
02
dict = {"a" : "apple", "b" :
"grape", "c" : "orange", "d" :
"banana"}
03
print (dict)
04
#按照key排序
05
print (sorted(dict.items(), key=lambda d: d[0]))
06
#按照value排序
07
print (sorted(dict.items(), key=lambda d: d[1]))
【代碼說明】
·第3行代碼輸出字典dict的結果如下。
{'a' : 'apple', 'b' : 'grape', 'c' :
'orange', 'd' : 'banana'}
·第5行代碼把dict.items()作為需要排序的集合,items()前面已經提到,它可以用於字典的遍歷,並返回(key,value)元組組成的列表。參數key表示排序的“依據”,d[0]表示items()中的key,即按照key值進行排序。lambda可以創建匿名函數,用於返回一些計算結果,lambda的使用請參考第5章的內容。排序後的結果:
[('a', 'apple'), ('b', 'grape'), ('c',
'orange'), ('d', 'banana')]
·第7行代碼按照dict.items()中的value值進行排序。排序後的結果:
[('a', 'apple'), ('d', 'banana'), ('b',
'grape'), ('c', 'orange')]
前面提到了update(),這個方法把字典A的內容複製到字典B中,且字典B中原有的內容保持不變,從而實現了字典B的擴展。如果需要把字典A的內容複製到字典B,並清除字典B中原有的內容,可以使用copy()。copy()聲明如下所示。
D.copy() -> a shallow copy of D
copy()實現了字典的淺拷貝操作,後面還會提到深拷貝的概念以及它們的區別,目前讀者只需知道該方法的使用。下麵這段代碼演示了字典的複製操作。
01
#字典的淺拷貝
02
dict = {"a" : "apple", "b" :
"grape"}
03
dict2 = {"c" : "orange", "d" :
"banana"}
04
dict2 = dict.copy() # 拷貝dict並賦給dict2
05
print (dict2)
【代碼說明】 第4行代碼把字典dict的內容複製給dict2。字典dict2的輸出結果:
{'a': 'apple', 'b': 'grape'}
深拷貝能夠拷貝物件內部所有的資料和引用,引用相當於C語言中指標的概念,Python並不存在指標,但是變數的記憶體結構中通過引用來維護變數。而淺拷貝只是複製資料,並沒有複製資料的引用,新的資料和舊的資料使用同一塊記憶體空間。
例如,字典B淺拷貝字典A的資料,如果字典B的資料發生添加、刪除或修改操作,字典A的資料也將發生變化;相反,如果字典B深拷貝字典A的資料,字典B的資料即使發生變化,也不會影響到字典A。
深拷貝和淺拷貝可以應用於Python的任何物件,不只是限於字典。在Python中可以使用copy模組來實現物件的深拷貝和淺拷貝,deepcopy()用於深拷貝操作,copy()用於淺拷貝操作。
下麵這段代碼演示了淺拷貝和深拷貝的區別。
01
#字典的深拷貝
02
import copy
03
dict = {"a" : "apple", "b" :
{"g" : "grape","o" : "orange"}}
04
dict2 = copy.deepcopy(dict)
# 深拷貝
05
dict3 = copy.copy(dict)
# 淺拷貝
06
dict2["b"]["g"] = "orange"
07
print (dict)
08
dict3["b"]["g"] = "orange"
09
print (dict)
【代碼說明】
·第2行代碼導入了copy模組。在使用deepcopy()和copy()前,必須先導入copy模組。
·第4行代碼字典dict2深拷貝字典dict。
·第5行代碼字典dict3淺拷貝字典dict,copy.copy()的作用等價於dict.copy()。
·第6行代碼改變了字典dict2中的資料。
·第7行代碼中字典dict並不會受字典dict2的影響,字典dict的資料保持不變。字典dict的輸出結果:
{'a': 'apple', 'b': {'o': 'orange', 'g':
'grape'}}
·第8行代碼改變了字典dict3中的資料。
·第9行代碼中字典dict受字典dict3的資料改變的影響。字典dict的輸出結果:
{'a': 'apple', 'b': {'o': 'orange', 'g':
'orange'}}
4.3.5 全域字典——sys.modules模組
sys.modules是一個全域字典,這個字典是Python啟動後就載入在記憶體中的。每當程式師導入新的模組,sys.modules都將記錄這些模組。字典sys.modules對載入模組起到了緩存的作用。當某個模組第一次導入時,字典sys.modules將自動記錄該模組。當第2次再導入此模組時,Python會直接到字典中查找,從而加快了程式運行的速度。
字典sys.modules具有字典所擁有的一切方法,可以通過這些方法瞭解當前的環境載入了哪些模組。下面這段代碼調用了字典的keys()和values()方法,keys()返回當前環境下載入的模組,values()返回這些模組引用路徑。
01
import sys
02
print (sys.modules.keys())
03
print (sys.modules.values())
04
print (sys.modules["os"])
【代碼說明】
·第2行代碼keys()返回sys模組以及Python自動載入的模組。輸出結果:
['copy_reg', 'sre_compile', 'locale', '_sre', '__main__', 'site', '__builtin__',
'operator', 'encodings', 'os.path', 'encodings.encodings', 'encodings.gbk',
'errno', 'encodings.codecs', 'sre_constants', 're', 'ntpath', 'UserDict',
'encodings._multibytecodec', 'nt', 'stat', 'zipimport', 'warnings', 'encodings.types',
'_codecs', '_multibytecodec', 'sys', 'codecs', 'types', '_types', '_codecs_cn',
'_locale', 'signal', 'linecache', 'encodings.aliases', 'exceptions',
'sre_parse', 'os', 'encodings._codecs_cn']
·第3行代碼values()返回的模組引用。
·第4行代碼返回索引“os”對應的引用。輸出結果:
<module 'os' from
'D:\developer\python\lib\os.pyc'>
下麵這段代碼實現了導入模組的過濾。
01
import sys
02
d = sys.modules.copy()
03
import copy,string
04
print (zip(set(sys.modules) - set(d)))
# 使用zip進行modules的過濾
【代碼說明】
·第2行代碼調用copy(),把當前導入的模組資訊保存到字典d中。
·第3行代碼導入模組copy、string,此時的字典sys.modules包含了原有的模組和新導入的模組。
·第4行代碼調用set()把字典sys.modules、字典d存入set集合中,set集合實現了減法運運算元,set(sys.modules)-set(d)將返回字典d中沒有、而字典sys.modules中存在的模組。然後調用zip()對set集合“解包”,返回一個列表。該列表就是使用import
copy,string語句導入的模組。輸出結果:
[('copy',), ('strop',), ('string',)]
4.4 序列
序列是具有索引和切片能力的集合。元組、清單和字串具有通過索引訪問某個具體的值,或通過切片返回一段切片的能力,因此元組、清單和字串都屬於序列。下面這段代碼演示了序列的索引功能。
01
#索引操作
02
tuple = ("apple", "banana", "grape",
"orange")
03
list = ["apple", "banana", "grape",
"orange"]
04
str = "apple"
05
print (tuple[0])
06
print (tuple[-1])
07
print (list[0])
08
print (list[-1])
09
print (str[0])
10
print (str[-1])
【代碼說明】
·第5、6行代碼訪問元組的第1個元素和最後一個元素。輸出結果:
apple
orange
·第7、8行代碼訪問清單的第1個元素和最後一個元素。輸出結果:
apple
orange
·第9、10行代碼訪問字串的第1個字元和最後一個字元。輸出結果:
a
e
下面這段代碼演示了序列的分片功能。
01
#分片操作
02
tuple = ("apple", "banana", "grape",
"orange")
03
list = ["apple",
"banana", "grape", "orange"]
04
str = "apple"
05
print (tuple[:3])
06
print (tuple[3:])
07
print (tuple[1:-1])
08
print (tuple[:])
09
print (list[:3])
10 print (list[3:])
11
print (list[1:-1])
12
print (list[:])
13
print (str[:3])
14
print (str[3:])
15
print (str[1:-1])
16
print (str[:])
【代碼說明】
·第5~8行代碼依次輸出如下。
('apple', 'banana', 'grape')
('orange',)
('banana', 'grape')
('apple', 'banana', 'grape', 'orange')
·第9~12行代碼依次輸出如下。
['apple', 'banana', 'grape']
['orange',]
['banana', 'grape']
['apple', 'banana', 'grape', 'orange']
·第13~16行代碼依次輸出如下。
app
le
ppl
apple
注意 分片seq[:3]表示從序列第1個元素到第3個元素的值,分片[:]獲得整個序列的值。
元組和列表都具有序列的特性,但是它們的區別也很明顯。元組是唯讀的一組資料,而且元組沒有提供排序和查找的方法。清單的資料可讀寫,而且提供豐富的操作方法,支援排序、查找操作。元組的資料通常具有不同的含義,例如座標(x,y)可以表示為一個元組,x軸座標和y軸座標的含義是不同的。清單的資料通常具有相同的含義,例如[(x1,y1),(x2,y2)]表示為一個列表,這個列表中有兩組座標值,每組座標表示的意義是相同的,它們都表示直角坐標系中的某個位置。表4-3說明了元組和列表的區別。
表4-3 元組和列表的區別
4.5 小結
本章介紹了Python內置的幾種資料結構,這些內置的資料結構是使用Python進行開發的基礎。其中,重點講解了使用清單實現堆疊和佇列的原理以及實現過程,以及清單、字典中常用方法的使用。最後通過具體的例子闡述了元組、列表和序列之間的關係,描述了元組和列表的區別。
下一章將講解函數的知識,函數的參數、返回值都非常頻繁地使用本章這些資料結構。讀者需要多理解本章的內容,為後面的學習打好基礎。
4.6 習題
1.給定列表L,如[2,5,3,8,10,1],對其進行昇冪排序並輸出。
2.給定字串s,如'123456',將其逆序並輸出。(提示:使用切片)
3.給定字典d,如{'a':1,'b':2,'c':3},分別輸出它的key與value。向其中插入字典{'d':4},並輸出新的字典。
4.求出100以內的所有素數,素數之間使用逗號隔開。





0 留言:
發佈留言