《Python從小白到大?!芬呀?jīng)上市!
當(dāng)你有很多書時(shí),你會(huì)考慮買一個(gè)書柜,將你的書分門別類擺放進(jìn)入。使用了書柜不僅僅使房間變得整潔,也便于以后使用書時(shí)方便查找。在計(jì)算機(jī)程序中會(huì)有很多數(shù)據(jù),這些數(shù)據(jù)也需要一個(gè)容器將他們管理起來,這就是數(shù)據(jù)結(jié)構(gòu)。常見的數(shù)據(jù)結(jié)構(gòu):數(shù)組(Array)、集合(Set)、列表(List)、隊(duì)列(Queue)、鏈表(Linkedlist)、樹(Tree)、堆(Heap)、棧(Stack)和字典(Dictionary)等結(jié)構(gòu)。
Python中數(shù)據(jù)容器主要有:序列、集合和字典。
注意
Python中并沒有數(shù)組結(jié)構(gòu),因?yàn)閿?shù)組要求元素類型是一致的。而Python作為動(dòng)態(tài)類型語言,不強(qiáng)制聲明變量的數(shù)據(jù)類型,也不能強(qiáng)制檢查元素的數(shù)據(jù)類型。所以Python中沒有數(shù)組結(jié)構(gòu)。
元組(tuple)是一種序列(sequence)結(jié)構(gòu),下面先來介紹一些序列。
序列(sequence)是一種可迭代的^1,元素是有序的,可以重復(fù)出現(xiàn)的數(shù)據(jù)結(jié)構(gòu)。序列可以通過索引訪問元素。圖9-1是一個(gè)班級序列,其中有一些學(xué)生,這些學(xué)生是有序的,順序是他們被放到序列中的順序,可以通過序號訪問他們。這就像老師給進(jìn)入班級的人分配學(xué)號,第一個(gè)報(bào)到的是“張三”,老師給他分配的是0,第二個(gè)報(bào)到的是“李四”,老師給他分配的是1,以此類推,最后一個(gè)序號應(yīng)該是“學(xué)生人數(shù)-1”。
序列包括的結(jié)構(gòu)有:列表(list)、字符串(str)、元組(tuple)、范圍(range)、和字節(jié)序列(bytes)。序列可進(jìn)行的操作有:索引、分片、加和乘。
序列中第一個(gè)元素的索引是0,其他元素的索引是第一個(gè)元素的偏移量。可以有正偏移量,稱為正值索引;也可以有負(fù)偏移量,稱為負(fù)值索引。正值索引最后一個(gè)元素索引是“序列長度-1”,負(fù)值索引最后一個(gè)元素索引是“-1”。例如Hello字符串,它的正值索引如圖9-2(a)所示,它的負(fù)值索引如圖9-2(b)所示。
訪問序列中的元素的通過索引下標(biāo)訪問的,即中括號[index]方式訪問。在Python
Shell中運(yùn)行示例如下:
>>> a = 'Hello'
>>> a[0]
'H'
>>> a[1]
'e'
>>> a[4]
'o'
>>> a[-1]
'o'
>>> a[-2]
'l'
>>> a[5]
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
a[5]
IndexError: string index out of range
>>> max(a)
'o'
>>> min(a)
'H'
>>> len(a)
5
a[0]是訪問序列第一個(gè)元素,最后一個(gè)元素的索引可以是4或-1。但是索引超過范圍,則會(huì)發(fā)生IndexError錯(cuò)誤。另外,獲取序列的長度使用函數(shù)len,類似的序列還有max和min函數(shù),max函數(shù)返回最后一個(gè)元素,min函數(shù)返回第一個(gè)元素。??
下面看看序列的加和乘,在前面第7章介紹+和*運(yùn)算符時(shí),提到過他們可以應(yīng)用于序列。+運(yùn)算符可以將兩個(gè)序列連接起來,*運(yùn)算符可以將重復(fù)多次。
在Python Shell中運(yùn)行示例:
>>> a = 'Hello'
>>> a * 3
'HelloHelloHello'
>>> print(a)
Hello
>>> a += ' '
>>> a += 'World'
>>> print(a)
Hello World
序列的分片(Slicing)就是從序列中切分出小的子序列。分片使用分片運(yùn)算符,分片運(yùn)算符有兩種形式:
[start:end]。start是開始索引,end是結(jié)束索引。
注意
切下的分片包括start位置元素,但不包括end位置元素,start和end都可以省略。
在Python Shell中運(yùn)行示例代碼如下:
>>> a[1:3]
'el'
>>> a[:3]
'Hel'
>>> a[0:3]
'Hel'
>>> a[0:]
'Hello'
>>> a[0:5]
'Hello'
>>> a[:]
'Hello'
>>> a[1:-1]
'ell'
上述代碼表達(dá)式a[1:3]是切出1\~3之間的子字符串,注意不包括3,所以結(jié)果是el。表達(dá)式a[:3]省略了開始索引,默認(rèn)開始索引是0,所以a[:3]與a[0:3]分片結(jié)果是一樣的。表達(dá)式a[0:]省略了結(jié)束索引,默認(rèn)結(jié)束索引是序列的長度,即5。所以a[0:]
與a[0:5]分片結(jié)果是一樣的。表達(dá)式a[:]是省略了開始索引和結(jié)束索引,a[:]與a[0:5]結(jié)果一樣。
另外,表達(dá)式a[1:-1]使用了負(fù)值索引,對照圖9-1所示,不難計(jì)算出a[1:-1]結(jié)果是ell。
分片時(shí)使用[start:end:step]可以指定步長(step),步長與當(dāng)次元素索引、下次元素索引之間的關(guān)系如下:
> 下次元素索引 = 當(dāng)次元素索引 + 步長
在Python Shell中運(yùn)行示例代碼如下:
>>> a[1:5]
'ello'
>>> a[1:5:2]
'el'
>>> a[0:3]
'Hel'
>>> a[0:3:2]
'Hl'
>>> a[0:3:3]
'H'
>>> a[::-1]
'olleH'
表達(dá)式a[1:5]省略了步長參數(shù),步長默認(rèn)值是1。表達(dá)式a[1:5:2]是步長為2,結(jié)果是el。a[0:3]分片后的字符串是Hel。而a[0:3:3]是步長為3,分片結(jié)果H字符了。當(dāng)步長為負(fù)數(shù)時(shí)比較麻煩,負(fù)數(shù)時(shí)是從右往左獲取元素,所以表達(dá)式a[::-1]分片的結(jié)果是原始字符串的倒置。
元組(tuple)是一種不可變序列,一旦創(chuàng)建就不能修改。創(chuàng)建元組可以使用tuple([iterable])函數(shù)或者直接用逗號(,)將元素分隔。
在Python Shell中運(yùn)行示例代碼如下:
>>> 21,32,43,45 ①
(21, 32, 43, 45)
>>> (21, 32, 43, 45) ②
(21, 32, 43, 45)
>>> a = (21,32,43,45)
>>> print(a)
(21, 32, 43, 45)
>>> ('Hello', 'World') ③
('Hello', 'World')
>>> ('Hello', 'World', 1,2,3)④
('Hello', 'World', 1, 2, 3)
>>> tuple([21,32,43,45]) ⑤
(21, 32, 43, 45)
代碼第①行創(chuàng)建了一個(gè)有4個(gè)元素的元組,創(chuàng)建元組時(shí)使用小括號把元素包裹起來不是必須的。代碼第②行使用括號將元素包裹起來,這只是為了提高程序的可讀性。Python中沒有強(qiáng)制聲明數(shù)據(jù)類型,因此元組中的元素可以是任何數(shù)據(jù)類型,代碼第③行創(chuàng)建是一個(gè)字符串元組,代碼第④行是創(chuàng)建字符串和整數(shù)混合的元組。
另外,元組還有通過tuple([iterable])函數(shù)創(chuàng)建,參數(shù)iterable是任何可迭代對象。代碼第⑤行是使用tuple()函數(shù)創(chuàng)建元組對象,實(shí)參[21,32,43,45]是一個(gè)列表,列表是可迭代對象,可以作為tuple()函數(shù)參數(shù)創(chuàng)建元組對象。
創(chuàng)建元組還需要注意如下極端情況:
>>> a = (21)
>>> type(a)
<class 'int'>
>>> a = (21,)
>>> type(a)
<class 'tuple'>
>>> a = ()
>>> type(a)
<class 'tuple'>
從上述代碼可見,如果一個(gè)元組只有一個(gè)元素時(shí),后面的逗號不能省略,即(21,)表示的是只有一個(gè)元素的元組,而(21)表示的是一個(gè)整數(shù)。另外,()可以創(chuàng)建空元組。
元組做為序列可以通過下標(biāo)索引訪問元素,也可以對其進(jìn)行分片。在Python
Shell中運(yùn)行示例代碼如下:
>>> a = ('Hello', 'World', 1,2,3) ①
>>> a[1]
'World'
>>> a[1:3]
('World', 1)
>>> a[2:]
(1, 2, 3)
>>> a[:2]
('Hello', 'World')
上述代碼第①行是元組a,a[1]是訪問元組第二個(gè)元素,表達(dá)式a[1:3]、a[2:]和a[:2]都是進(jìn)行分片操作。
元組還可以進(jìn)行拆包(Unpack)操作,就是將元組的元素取出賦值給不同變量。在Python Shell中運(yùn)行示例代碼如下:
>>> a = ('Hello', 'World', 1,2,3)
>>> str1, str2, n1,n2, n3 = a ①
>>> str1
'Hello'
>>> str2
'World'
>>> n1
1
>>> n2
2
>>> n3
3
>>> str1, str2, *n = a ②
>>> str1
'Hello'
>>> str2
'World'
>>> n
[1, 2, 3]
>>> str1,_,n1,n2,_ = a ③
上述代碼第①行是將元組a進(jìn)行拆包操作,接收拆包元素的變量個(gè)數(shù)應(yīng)該等于元組個(gè)數(shù)相同。接收變量個(gè)數(shù)也可以少于元組個(gè)數(shù),代碼第②行接收變量個(gè)數(shù)只有3個(gè),最后一個(gè)很特殊,變量n前面有星號,表示將剩下的元素作為一個(gè)列表賦值給變量n。另外,還可以使用下劃線指定哪些元素不取值,代碼第行是不取第二個(gè)和第五個(gè)元素。
遍歷元組一般是使用for循環(huán),示例代碼如下:
# coding=utf-8
# 代碼文件:chapter9/ch9.1.4.py
a = (21, 32, 43, 45)
for item in a: ①
print(item)
print('-----------')
for i, item in enumerate(a): ②
print('{0} - {1}'.format(i, item))
輸出結(jié)果如下:
21
32
43
45
-----------
0 - 21
1 - 32
2 - 43
3 – 45
一般情況下遍歷目的只是取出每一個(gè)元素值,見代碼第①行的for循環(huán)。但有時(shí)需要在遍歷過程中同時(shí)獲取索引,則可以使用代碼第②行的for循環(huán),其中enumerate(a)函數(shù)可以獲得元組對象,該元組對象有兩個(gè)元素,第一個(gè)元素是索引,第二個(gè)元素是數(shù)值。所以i,
item是元組拆包過程,最后變量i是元組a的當(dāng)前索引,item是元組a的當(dāng)前元素值。
注意
本節(jié)雖然介紹的是元組的遍歷,上述遍歷方式適合于所有序列,如字符串、范圍和列表等。
列表(list)也是一種序列結(jié)構(gòu),與元組不同列表具有可變性,可以追加、插入、刪除和替換列表中的元素。
創(chuàng)建列表可以使用list([iterable])函數(shù),或者用中括號[]將元素包裹,元素之間用逗號分隔。在Python Shell中運(yùn)行示例代碼如下:
>>> [20, 10, 50, 40, 30] ①
[20, 10, 50, 40, 30]
>>> []
[]
>>> ['Hello', 'World', 1, 2, 3] ②
['Hello', 'World', 1, 2, 3]
>>> a = [10] ③
>>> type(a)
<class 'list'>
>>> a = [10,] ④
>>> type(a)
<class 'list'>
>>> list((20, 10, 50, 40, 30)) ⑤
[20, 10, 50, 40, 30]
上述代碼第①行創(chuàng)建一個(gè)有5個(gè)元素的列表,注意中括號不能省略,如果省略了中括號那就變成了元組了。創(chuàng)建空列表是[]表達(dá)式。列表中可以放入任何對象,代碼第②行是創(chuàng)建一個(gè)字符串和整數(shù)混合的列表。代碼第③行是創(chuàng)建只有一個(gè)元素的列表,中括號不能省略。另外,無論是元組還是列表,每一個(gè)元素后面都跟著一個(gè)逗號,只是最后一個(gè)元素的逗號經(jīng)常是省略的,代碼第④行最后一個(gè)元素沒有省略逗號。
另外,列表還有通過list([iterable])函數(shù)創(chuàng)建,參數(shù)iterable是任何可迭代對象。代碼第⑤行是使用list()函數(shù)創(chuàng)建列表對象,實(shí)參(20,
10, 50, 40,
30)是一個(gè)元組,元組是可迭代對象,可以作為list()函數(shù)參數(shù)創(chuàng)建列表對象。
列表中追加單個(gè)元素可以使用append()方法追加單個(gè)元素。如果想追加另一列表,可以使用+運(yùn)算符或extend()方法。
append()方法語法:
list.append(x)
其中x參數(shù)是要追加單個(gè)元素值。
extend()方法語法:
list.extend(t)
其中t參數(shù)是要追加的另外一個(gè)列表。
在Python Shell中運(yùn)行示例代碼如下:
>>> student_list = ['張三', '李四', '王五']
>>> student_list.append('董六') ①
>>> student_list
['張三', '李四', '王五', '董六']
>>> student_list += ['劉備', '關(guān)羽'] ②
>>> student_list
['張三', '李四', '王五', '董六', '劉備', '關(guān)羽']
>>> student_list.extend(['張飛', '趙云']) ③
>>> student_list
['張三', '李四', '王五', '董六', '劉備', '關(guān)羽', '張飛', '趙云']
上述代碼中第①行使用了append方法,在列表后面追加一個(gè)元素,append()方法不能同時(shí)追加多個(gè)元素。代碼第②行是利用+=運(yùn)算符追加多個(gè)元素,能夠支持+=運(yùn)算是因?yàn)榱斜碇С?運(yùn)算。代碼第③行是使用extend()方法追加多個(gè)元素。
插入元素可以使用列表的insert()方法,該方法可以在指定索引位置,插入一個(gè)元素。insert()方法語法:
list.insert(i, x)
其中參數(shù)i是要插入的索引,參數(shù)x是要插入的元素?cái)?shù)值。
在Python Shell中運(yùn)行示例代碼如下:
>>> student_list = ['張三', '李四', '王五']
>>> student_list.insert(2, '劉備')
>>> student_list
['張三', '李四', '劉備', '王五']
上述代碼中student_list調(diào)用insert方法,在索引2位置插入一個(gè)元素,新元素的索引為2。
列表具有可變性,其中的元素替換,替換元素很簡單,通過列表下標(biāo)索引元素放在賦值符號(=)左邊,進(jìn)行賦值即可替換。在Python
Shell中運(yùn)行示例代碼如下:
>>> student_list = ['張三', '李四', '王五']
>>> student_list[0] = "諸葛亮"
>>> student_list
['諸葛亮', '李四', '劉備', '王五']
其中student_list[0] = "諸葛亮"是替換列表student_list的第一個(gè)元素。
列表中實(shí)現(xiàn)刪除元素的方式有兩種:一種是使用列表的remove()方法;另一種是使用列表的pop()方法。
remove()方法從左往右查找列表中的元素,如果找到匹配元素則刪除,注意如果找到多個(gè)匹配元素,只是刪除第一個(gè)。如果沒有找到則會(huì)拋出錯(cuò)誤。
remove()方法語法:
list.remove(x)
其中x參數(shù)是要找到元素值。
使用remove()方法刪除元素,示例代碼如下:
>>> student_list = ['張三', '李四', '王五', '王五']
>> student_list.remove('王五')
>>> student_list
['張三', '李四', '王五']
>>> student_list.remove('王五')
>>> student_list
['張三', '李四']
pop()方法也會(huì)刪除列表中的元素,但它會(huì)將成功刪除的元素返回。pop()方法語法如下:
item = list.pop([i])
參數(shù)i是指定刪除元素的索引,i可以省略,表示刪除最后一個(gè)元素。返回值item是刪除的元素。
使用pop()方法刪除元素示例代碼如下:
>>> student_list = ['張三', '李四', '王五']
>>> student_list.pop()
'王五'
>>> student_list
['張三', '李四']
>>> student_list.pop(0)
'張三'
>>> student_list
['李四']
前面介紹列表追加、插入和刪除時(shí),已經(jīng)介紹了一些方法。事實(shí)上列表還有很多方法,本節(jié)再介紹幾個(gè)常用的方法。包括:
reverse()。倒置列表。
copy()。復(fù)制列表。
clear()。清除列表中的所有元素。
index(x[, i[,
j]])。返回查找x第一次出現(xiàn)的索引,i是開始查找索引,j是結(jié)束查找索引。該方法繼承自序列,元組和字符串也可以使用該方法。
在Python Shell中運(yùn)行示例代碼如下:
>>> a = [21, 32, 43, 45]
>>> a.reverse() ①
>>> a
[45, 43, 32, 21]
>>> b = a.copy() ②
>>> b
[45, 43, 32, 21]
>>> a.clear() ③
>>> a
[]
>>> b
[45, 43, 32, 21]
>>> a = [45, 43, 32, 21, 32]
>>> a.count(32) ④
2
>>> student_list = ['張三', '李四', '王五']
>>> student_list.index('王五') ⑤
2
>>> student_tuple = ('張三', '李四', '王五')
>>> student_tuple.index('王五') ⑥
2
>>> student_tuple.index('李四', 1 , 2)
1
上述代碼中第①行是調(diào)用reverse()方法將列表a倒置。代碼第②行是調(diào)用copy()方法復(fù)制a,并賦值給b。代碼第③行是清除a中元素。代碼第④行是返回a列表中32元素的個(gè)數(shù)。代碼第⑤行是返回'王五'在student_list列表中的位置。代碼第⑥行是返回'王五'在student_tuple元組中的位置。
Python中有一種特殊表達(dá)式——推導(dǎo)式,它可以將一種數(shù)據(jù)結(jié)構(gòu)作為輸入,經(jīng)過過濾、計(jì)算等處理,最后輸出另一種數(shù)據(jù)結(jié)構(gòu)。根據(jù)數(shù)據(jù)結(jié)構(gòu)的不同分為:列表推導(dǎo)式、集合推導(dǎo)式和字典推導(dǎo)式。本節(jié)先介紹列表推導(dǎo)式。
如果想獲得0\~9中偶數(shù)的平方數(shù)列,那么可以通過for循環(huán)實(shí)現(xiàn),代碼如下:
# coding=utf-8
# 代碼文件:chapter9/ch9.2.7.py
n_list = []
for x in range(10):
if x % 2 == 0:
n_list.append(x ** 2)
print(n_list)
輸出結(jié)構(gòu)如下:
[0, 4, 16, 36, 64]
0\~9中偶數(shù)的平方數(shù)列可以通過列表推導(dǎo)式實(shí)現(xiàn),代碼如下:
n_list = [x ** 2 for x in range(10) if x % 2 == 0] ①
print(n_list)
上述代碼其中代碼第行就是列表推導(dǎo)式,輸出的結(jié)果與for循環(huán)是一樣的。圖9-3所示是列表推導(dǎo)式語法結(jié)構(gòu),其中in后面的表達(dá)式是“輸入序列”;for前面的表達(dá)式是“輸出表達(dá)式”它運(yùn)算結(jié)果會(huì)保存一個(gè)新列表中;if條件語句是過濾輸入序列,符合條件的才傳遞給輸出表達(dá)式,“條件語句”是可以省略的,也是所有元素都傳遞給輸出表達(dá)式。
條件語句可以包含多個(gè)條件,如果想找出0\~99之間的偶數(shù),而且可以被5整除數(shù)列,實(shí)現(xiàn)代碼如下:
n_list = [x for x in range(100) if x % 2 == 0 if x % 5 == 0]
print(n_list)
列表推導(dǎo)式的條件語句有兩個(gè)if x % 2 == 0和if x % 5 == 0,可見他們“與”的關(guān)系。
集合(set)是一種可迭代的、無序的、不能包含重復(fù)元素的數(shù)據(jù)結(jié)構(gòu)。圖9-4是一個(gè)班級的集合,其中包含一些學(xué)生,這些學(xué)生是無序的,不能通過序號訪問,而且不能有重復(fù)的同學(xué)。
提示
如果與序列比較,序列中的元素是有序的,可以重復(fù)出現(xiàn),而集合中是無序的,不能重復(fù)的元素。序列強(qiáng)調(diào)的是有序,集合強(qiáng)調(diào)的是不重復(fù)。當(dāng)不考慮順序,而且沒有重復(fù)的元素時(shí),序列和集合可以互相替換。
集合又分為可變集合(set)和不可變集合(frozenset)。
可變集合類型是set,創(chuàng)建可變集合可以使用set([iterable])函數(shù),或者用大括號{}將元素包裹,元素之間用逗號分隔。在Python
Shell中運(yùn)行示例代碼如下:
>>> a = {'張三', '李四', '王五'} ①
>>> a
{'張三', '李四', '王五'}
>>> a = {'張三', '李四', '王五', '王五'}②
>>> len(a)
3
>>> a
{'張三', '李四', '王五'}
>>> set((20, 10, 50, 40, 30)) ③
{40, 10, 50, 20, 30}
>>> b = {} ④
>>> type(b)
<class 'dict'>
>>> b = set() ⑤
>>> type(b)
<class 'set'>
上述代碼第①行是使用大括號創(chuàng)建集合,如果元素有重復(fù)的會(huì)怎樣呢?代碼第②行包含有重復(fù)的元素,創(chuàng)建時(shí)會(huì)剔除重復(fù)元素。代碼第③行是使用set()函數(shù)創(chuàng)建集合對象。如果要?jiǎng)?chuàng)建一個(gè)空的集合不能使用{}表示,見代碼第④行b并不是集合而是字典,而是使用空參數(shù)的set()函數(shù),見代碼第⑤行。
提示
要獲得集合中元素的個(gè)數(shù),可以使用len()函數(shù),注意len()是函數(shù)不是方法,本例中l(wèi)en(a)表達(dá)式返回集合a的元素個(gè)數(shù)。
可變集合類似于列表,可變集合內(nèi)容可以被修改,可以插入和刪除元素。修改可變集合幾個(gè)常用的方法。包括:
add(elem)。添加元素,如果元素已經(jīng)存在,則不能添加,不會(huì)拋出錯(cuò)誤。
remove(elem)。刪除元素,如果元素不存在,則拋出錯(cuò)誤。
discard(elem)。刪除元素,如果元素不存在,不會(huì)拋出錯(cuò)誤。
pop()。刪除返回集合中任意一個(gè)元素,返回值是刪除的元素。
在Python Shell中運(yùn)行示例代碼如下:
>>> student_set = {'張三', '李四', '王五'}
>>> student_set.add('董六')
>>> student_set
{'張三', '董六', '李四', '王五'}
>>> student_set.remove('李四')
>>> student_set
{'張三', '董六', '王五'}
>>> student_set.remove('李四') ①
Traceback (most recent call last):
File "<pyshell#144>", line 1, in <module>
student_set.remove('李四')
KeyError: '李四'
>>> student_set.discard('李四') ②
>>> student_set
{'張三', '董六', '王五'}
>>> student_set.discard('王五')
>>> student_set
{'張三', '董六'}
>>> student_set.pop()
'張三'
>>> student_set
{'董六'}
>>> student_set.clear()
>>> student_set
set()
上述代碼第①行使用remove()方法刪除元素時(shí),由于要?jiǎng)h除的'李四'已經(jīng)不在集合中,所以會(huì)拋出錯(cuò)誤。而同樣是刪除集合中不存在的元素discard()方法不會(huì)拋出錯(cuò)誤,見代碼第②行。
集合是無序的,沒有索引,不能通過下標(biāo)訪問單個(gè)元素。但可以遍歷集合,訪問集合每一個(gè)元素。
遍歷集合一般是使用for循環(huán),示例代碼如下:
# coding=utf-8
# 代碼文件:chapter9/ch9.3.3.py
student_set = {'張三', '李四', '王五'}
for item in student_set:
print(item)
print('-----------')
for i, item in enumerate(student_set): ①
print('{0} - {1}'.format(i, item))
輸出結(jié)果如下:
張三
王五
李四
-----------
0 - 張三
1 - 王五
2 - 李四
上述中使用for循環(huán)遍歷集合,代碼第①行的for循環(huán)中使用了enumerate()函數(shù),該還是在9.1.4節(jié)遍歷元組時(shí)已經(jīng)介紹過了,但是需要注意的是,此時(shí)變量i不是索引,只是遍歷集合的次數(shù)。
不可變集合類型是frozenset,創(chuàng)建不可變集合使用frozenset([iterable])函數(shù),不能使用大括號{}。在Python Shell中運(yùn)行示例代碼如下:
>>> student_set = frozenset({'張三', '李四', '王五'}) ①
>>> student_set
frozenset({'張三', '李四', '王五'})
>>> type(student_set)
<class 'frozenset'>
>>> student_set.add('董六') ②
Traceback (most recent call last):
File "<pyshell#168>", line 1, in <module>
student_set.add('董六')
AttributeError: 'frozenset' object has no attribute 'add'
>>> a = (21, 32, 43, 45)
>>> seta = frozenset(a) ③
>>> seta
frozenset({32, 45, 43, 21})
上述代碼第①行是創(chuàng)建不可變集合,frozenset()的參數(shù){'張三', '李四',
'王五'}是另一個(gè)集合對象,因?yàn)榧弦彩强傻鷮ο?,可以作為frozenset()的參數(shù)。代碼第③函數(shù)使用的了一個(gè)元組a作為frozenset()的參數(shù)。
由于創(chuàng)建的是不變集合,不能被修改,所以視圖修改發(fā)生錯(cuò)誤,見代碼第②行,使用add()發(fā)生錯(cuò)誤。
集合推導(dǎo)式與列表推斷式類似,區(qū)別只是輸出結(jié)構(gòu)是集合。修改9.2.7節(jié)代碼如下:
# coding=utf-8
# 代碼文件:chapter9/ch9.3.5.py
n_list = {x for x in range(100) if x % 2 == 0 if x % 5 == 0}
print(n_list)
輸出結(jié)構(gòu)如下:
{0, 70, 40, 10, 80, 50, 20, 90, 60, 30}
由于集合是不能有重復(fù)元素的,集合推導(dǎo)式輸出結(jié)果會(huì)過濾掉重復(fù)的元素,示例代碼如下:
input_list = [2, 3, 2, 4, 5, 6, 6, 6]
n_list = [x ** 2 for x in input_list] ①
print(n_list)
n_set = {x ** 2 for x in input_list} ②
print(n_set)
輸出結(jié)構(gòu)如下:
[4, 9, 4, 16, 25, 36, 36, 36]
{4, 36, 9, 16, 25}
上述代碼第①行是列表推導(dǎo)式。代碼第②行是集合推導(dǎo)式,從結(jié)果可見沒有重復(fù)的元素。
字典(dict)是可迭代的、可變的數(shù)據(jù)結(jié)構(gòu),通過鍵來訪問元素的數(shù)據(jù)結(jié)構(gòu)。字典結(jié)構(gòu)比較復(fù)雜,它是由兩部分視圖構(gòu)成的:一個(gè)是鍵(key)視圖;另一個(gè)是值(value)視圖。鍵視圖不能包含重復(fù)元素的,而值集合可以,鍵和值是成對出現(xiàn)的。
圖9-5所示是字典結(jié)構(gòu)的“國家代號”。鍵是國家代號,值是國家。
提示
字典更適合通過鍵快速訪問值,就像查英文字典一樣,鍵就是要查的英文單詞,而值是英文單詞的翻譯和解釋等內(nèi)容。有的時(shí)候,一個(gè)英文單詞會(huì)對應(yīng)多個(gè)翻譯和解釋,這也是與字典集合特性對應(yīng)的。
字典類型是dict,創(chuàng)建字典可以使用dict()函數(shù),或者用大括號{}將“鍵:值”對包裹,“鍵:值”對之間用逗號分隔。
在Python Shell中運(yùn)行示例代碼如下:
>>> dict1 = {102: '張三', 105: '李四', 109: '王五'} ①
>>> len(dict1)
3
>>> dict1
{102: '張三', 105: '李四', 109: '王五'}
>>> type(dict1)
<class 'dict'>
>>> dict1 = {}
>>> dict1
{}
>>> dict({102: '張三', 105: '李四', 109: '王五'}) ②
{102: '張三', 105: '李四', 109: '王五'}
>>> dict(((102, '張三'), (105, '李四'), (109, '王五'))) ③
{102: '張三', 105: '李四', 109: '王五'}
>>> dict([(102, '張三'), (105, '李四'), (109, '王五')]) ④
{102: '張三', 105: '李四', 109: '王五'}
>>> t1 = (102, '張三')
>>> t2 = (105, '李四')
>>> t3 = (109, '王五')
>>> t = (t1, t2, t3)
>>> dict(t) ⑤
{102: '張三', 105: '李四', 109: '王五'}
>>> list1 = [t1, t2, t3]
>>> dict(list1) ⑥
{102: '張三', 105: '李四', 109: '王五'}
>>> dict(zip([102, 105, 109], ['張三', '李四', '王五'])) ⑦
{102: '張三', 105: '李四', 109: '王五'}
上述代碼第①行是使用大括號“鍵:值”對創(chuàng)建字典,這是最簡單的創(chuàng)建字典方式了,那么創(chuàng)建一個(gè)空字典表達(dá)式是{}。獲得字典長度(鍵值對個(gè)數(shù))也是使用len()函數(shù)。
代碼第②行、第③行、第④行、第⑤行和第⑥行都用dict()函數(shù)創(chuàng)建字典。代碼第②行dict()函數(shù)參數(shù)是另外一個(gè)字典{102:
'張三', 105: '李四', 109: '王五'},使用這種方式不如直接使用大括號“鍵:值”。
代碼第③行和第⑤行參數(shù)是一個(gè)元組,這個(gè)元組中要包含三個(gè)只有兩個(gè)元素的元組,創(chuàng)建過程參考如圖9-6所示。代碼第④行和第⑥行參數(shù)是一個(gè)列表,這個(gè)列表中包含三個(gè)只有兩個(gè)元素的元組。
代碼第⑦行是使用zip()函數(shù),zip()函數(shù)將兩個(gè)可迭代對象打包成元組,在創(chuàng)建字典時(shí),可迭代對象元組,需要兩個(gè)可迭代對象,第一個(gè)是鍵([102,
105, 109]),第二個(gè)是值(['張三', '李四',
'王五']),他們包含的元素個(gè)數(shù)相同,并且一一對應(yīng)。
注意 使用dict()函數(shù)創(chuàng)建字典還可以使用一種key=value形式參數(shù),語法如下:
dict(key1=value1, key2=value2, key3=value3...)
key=value形式只能創(chuàng)建鍵是字符串類型的字典,使用時(shí)需要省略包裹字符串的引號(包括雙引號或單引號)。在Python
Shell中運(yùn)行示例代碼如下:\>\>\> dict(102 = '張三', 105 = '李四', 109 = '王五') ①
SyntaxError: keyword can't be an expression
\>\>\> dict('102' = '張三', '105' = '李四', '109' = '王五') ②
SyntaxError: keyword can't be an expression
\>\>\> dict(S102 = '張三', S105 = '李四', S109 = '王五') ③
{'S102': '張三', 'S105': '李四', 'S109': '王五'}
代碼第①行試圖通過上述dict()函數(shù)創(chuàng)建鍵是整數(shù)類型的字典,結(jié)果會(huì)發(fā)生錯(cuò)誤。代碼第②行是試圖使用字符串作為鍵創(chuàng)建字典,但是該dict()函數(shù)需要省略字符串鍵的引號,因此會(huì)發(fā)生錯(cuò)誤。需要注意本例中鍵是由數(shù)字構(gòu)成的字符串,他們很特殊如果省略包裹他們的引號,那么他們會(huì)表示為數(shù)字,使用該dict()函數(shù)是不允許的,所以此時(shí)的鍵不會(huì)識別字符串類型。代碼第③行的鍵是在數(shù)字前面加S字母,這樣不會(huì)識別為字符串類型。
字典可以被修改,但都是針對鍵和值同時(shí)操作,修改字典包括添加、替換和刪除“鍵:值”對。
在Python Shell中運(yùn)行示例代碼如下:
>>> dict1 = {102: '張三', 105: '李四', 109: '王五'}
>>> dict1[109] ①
'王五'
>>> dict1[110] = '董六' ②
>>> dict1
{102: '張三', 105: '李四', 109: '王五', 110: '董六'}
>>> dict1[109] = '張三' ③
>>> dict1
{102: '張三', 105: '李四', 109: '張三', 110: '董六'}
>>> del dict1[109] ④
>>> dict1
{102: '張三', 105: '李四', 110: '董六'}
>>> dict1.pop(105)
'李四'
>>> dict1
{102: '張三', 110: '董六'}
>>> dict1.pop(105, '董六') ⑤
'董六'
>>> dict1.popitem() ⑥
(110, '董六')
>>> dict1
{102: '張三'}
訪問字典中元素可通過下標(biāo)實(shí)現(xiàn),下標(biāo)參數(shù)是鍵,返回對應(yīng)的值,代碼第①行是dict1[109]是取出字典dict1中鍵為109的值。字典下標(biāo)訪問元素也可以在賦值符號(=)左邊,代碼第②行是字典110鍵賦值,注意此時(shí)字典dict1中沒有110鍵,那么這樣的操作會(huì)添加110:
'董六'鍵值對。如果鍵存在那么會(huì)替換對應(yīng)的值,代碼第③行會(huì)將鍵109對應(yīng)的值替換為'張三',雖然此時(shí)值視圖中已經(jīng)有'張三'了,但仍然可以添加,這說明值是可以重復(fù)的。
代碼第④行是刪除109鍵對應(yīng)的值,注意del是語句不是函數(shù)。使用del語句刪除鍵值對時(shí),如果鍵不存在會(huì)拋出錯(cuò)誤。
如果喜歡使用方法刪除元素,可以使用字典的pop(key[,
default])和popitem()方法。pop(key[,
default])方法刪除鍵值對,如果鍵不存在則返回默認(rèn)值(default),見代碼第⑤行是105鍵不存在返回默認(rèn)值'董六'。popitem()方法刪除任意鍵值對,返回刪除的鍵值對,構(gòu)成的元組,上述代碼第⑥行刪除了一個(gè)鍵值對,返回一個(gè)元組對象(110,
'董六')。
字典還一些方法用來訪問它的鍵或值,這些方法如下:
get(key[, default])。通過鍵返回值,如果鍵不存在返回默認(rèn)值。
items()。返回字典的所有鍵值對。
keys()。返回字典鍵視圖。
在Python Shell中運(yùn)行示例代碼如下:
>>> dict1 = {102: '張三', 105: '李四', 109: '王五'}
>>> dict1.get(105) ①
'李四'
>>> dict1.get(101) ②
>>> dict1.get(101, '董六') ③
'董六'
>>> dict1.items()
dict_items([(102, '張三'), (105, '李四'), (109, '王五')])
>>> dict1.keys()
dict_keys([102, 105, 109])
>>> dict1.values()
dict_values(['張三', '李四', '王五'])
上述代碼第①行是通過get()方法返回105鍵對應(yīng)的值,如果沒有鍵對應(yīng)的值,而且還沒有為get()方法提供默認(rèn)值,則不會(huì)有返回值,見代碼第②行。代碼第③行是提供了返回值。
在訪問字典時(shí),也可以使用in和not in運(yùn)算符,但是需要注意的是in和not
in運(yùn)算符只測試鍵視圖中進(jìn)行。在Python Shell中運(yùn)行示例代碼如下:
>>> student_dict = {'102': '張三', '105': '李四', '109': '王五'}
>>> 102 in dict1
True
>>> '李四' in dict1
False
字典遍歷也是字典的重要操作。與集合不同,字典有兩個(gè)視圖,因此遍歷過程可以只遍歷值視圖,也可以只遍歷鍵視圖,也可以同時(shí)遍歷。這些遍歷過程都是通過for循環(huán)實(shí)現(xiàn)的。
示例代碼如下:
# coding=utf-8
# 代碼文件:chapter9/ch9.4.4.py
student_dict = {102: '張三', 105: '李四', 109: '王五'}
print('---遍歷鍵---')
for student_id in student_dict.keys(): ①
print('學(xué)號:' + str(student_id))
print('---遍歷值---')
for student_name in student_dict.values(): ②
print('學(xué)生:' + student_name)
print('---遍歷鍵:值---')
for student_id, student_name in student_dict.items(): ③
print('學(xué)號:{0} - 學(xué)生:{1}'.format(student_id, student_name))
輸出結(jié)果如下:
---遍歷鍵---
學(xué)號:102
學(xué)號:105
學(xué)號:109
---遍歷值---
學(xué)生:張三
學(xué)生:李四
學(xué)生:王五
---遍歷鍵:值---
學(xué)號:102 - 學(xué)生:張三
學(xué)號:105 - 學(xué)生:李四
學(xué)號:109 - 學(xué)生:王五
上述代碼第③行遍歷字典的鍵值對,items()方法返回是鍵值對元組序列,student_id,
student_name是從元組拆包出來的兩個(gè)變量。
因?yàn)樽值浒随I和值兩個(gè)不同的結(jié)構(gòu),因此字典推導(dǎo)式結(jié)果可以非常靈活。字典推導(dǎo)示例代碼如下:
# coding=utf-8
# 代碼文件:chapter9/ch9.4.5.py
input_dict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
output_dict = {k: v for k, v in input_dict.items() if v % 2 == 0} ①
print(output_dict)
keys = [k for k, v in input_dict.items() if v % 2 == 0] ②
print(keys)
輸出結(jié)構(gòu)如下:
{'two': 2, 'four': 4}
['two', 'four']
上述代碼第①行是字典推導(dǎo)式,注意輸入結(jié)構(gòu)不能直接使用字典,因?yàn)樽值洳皇切蛄?,可以通過字典的item()方法返回字典中鍵值對序列。代碼第②行是字典推導(dǎo)式,但只返回鍵結(jié)構(gòu)。
本章介紹了Python中的幾種數(shù)據(jù)結(jié)構(gòu)。其中包括序列、元組、集合和字典,了解序列的特點(diǎn),清楚序列包括哪些結(jié)構(gòu)。然后詳細(xì)介紹了元組、集合和字典。
http://edu.51cto.com/sd/f907b
http://www.zhijieketang.com/group/8
作者微博:@tony_關(guān)東升郵箱:eorient@sina.com
br/>郵箱:eorient@sina.com
Python讀者服務(wù)QQ群:628808216
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。