第四章 當索引行不通時
第四章 當索引行不通時
需要將一系列值組合成資料結構並通過編號來訪問各個值時,列表很有用。本章將介紹一種可通過名稱來訪問其各個值的資料結構。這種資料結構稱為對映(mapping)。字典是Python中唯一的內建對映的型別,其中的值不按順序,而是儲存在鍵下。鍵可能是數,字串或元組。
4.1、字典的用途
字典的名稱指出了這種資料結構的用途。字典旨在讓你輕鬆地找到特定的單詞(鍵),以獲悉其定義(值)。
在很多情況下,使用字典都較為的合適。下面是Python字典的一些用途:
- 表示棋盤的狀態,其中每個鍵都是由座標組成的元組;
- 儲存檔案修改時間,其中的鍵為檔名;
- 數字電話/電話薄
4.2、建立和使用字典
字典以類似於下面的方式表示:
phonebook = {‘Alice’:‘2341’,‘Beth’:‘9102’,‘Ceil’:‘3258’}
字典由鍵及其相應的值組成,這種鍵-值對稱為項(item)。在前面的示例中,鍵為名字,而值為電話號碼。每個鍵與其值之間冒號( :)分隔,項之間用逗號分隔,而整個字典放在花括號內。空括號(沒有任何項)用兩個花括號表示,類似於下面這樣:{ }。
注意:在字典(以及其他對映型別)中,鍵必須是獨一無二的,而字典中的值無需如此。
4.2.1 函式dict
可使用函式dict從其他對映(如其他字典)或鍵-值對序列建立字典。
>>>items=[('name','Gumby'),('age',42)]
>>>d=dict(items)
>>>d
{'age':42,'name':'Gumby'}
>>>d['name']
'Gumby'
還可使用關鍵字實參來呼叫這個函式,如下所示:
>>>d=dict(name='Gumby',age=42}
>>>d
{'age':42,'name':GUmby'}
儘管這可能是函式dict最常見的使用者,但也可使用一個對映實參來呼叫它,這將建立一個字典,其中包含指定對映中的所有項。像函式list、tuple和str一樣,如果呼叫這個函式時沒有提供任何實參,將返回一個空字典。從對映建立字典時,如果該對映也是字典(畢竟字典時Python中唯一的內建對映型別),可不使用函式dict,而是使用字典方法copy,這將在本章後面介紹。
4.2.2 基本字典操作
字典的基本行為在很多方面都類似於序列:
- len(d)返回字典d包含的項(鍵-值對)數。
- d[k]返回鍵k相關聯的值。
- d[k] = v將值v關聯到鍵k。
- del d[k] 刪除鍵為k的項。
- k in d 檢查字典d是否包含鍵為k的項。
雖然字典和列表有多個相同之處,但也有一些重要的不同之處。
- 鍵的型別:字典裡的鍵可以說是整數,但並非必須是整數。字典中的鍵可以是任意不可變的
- 自動新增:即便是字典中原來沒有的鍵,也可以給它賦值,這將在字典中建立新項,然而,如果不適用append或者其他型別的方法,就不能給列表中沒有的元組賦值。
- 成員檢查:表示式k in d(其中d是一個字典)查詢的是鍵而不是值,而表示式v in l(其中l是列表)查詢的是值而不是索引。
提示:相比於檢查列表是否包含指定的值,檢查字典是否包含指定的鍵效率更高。資料結構越大,效率差距就越大
上述中已經提到了關於字典的第一個優點:鍵可以是任何不可變的型別;關於第二點,將會從下面的例子講出來:
x=[] x[42]='foobar'
上述的結果會出現下面的結果,思考一下,為什麼會出現這種現象:
Traceback (most recent call last): File "G:/Py_project/Python基礎教程/字典.py", line 2, in <module> x[42]='foobar' IndexError: list assignment index out of range
而針對字典的時候,我們在使用上述的方法的時候,顯然,這種方法就能夠正確的執行
x={} x[42]='foobar' print(x)
計算機將會執行處不一樣的結果:
{42: 'foobar'}
這是因為在列表中,Python中列表中的元素就像C語言中的陣列一樣,需要按順序存放,裡面分配多少空間才能夠用多少空間,而字典就不太一樣,字典則會分配成鍵和值,然後相對來說,如何使上述能的列表輸入正常,則需要通過列表中的None方法:
y=[None]*43 y[42]='foobar' print(y)
然後,結果就能夠被輸出:
[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 'foobar']
本文在下面進行了一個簡單的Python案例:
為字典案例:
people={ 'Alice':{ 'phone':'2341', 'addr' :'Foo drive 23' }, 'Beth' :{ 'phone':'9102', 'addr' :'Bar street 42' }, 'Cecil' : { 'phone':'3158', 'addr' :'Baz avenue 90' } } #電話號碼和地址的表述性標籤,供列印的時候使用 labels={ 'phone':'phone number', 'addr' :'address' } name=input('Name:') #要查詢電話號碼還是地址 request =input('Phone number(p) or address(a)?') #使用正確的鍵: if request =='p': key ='phone' if request =='a': key='addr' # 僅當名字是字典包含的鍵時才打印資訊 if name in people : print("{}'s {} is {}".format(name,labels[key],people[name][key]))
這樣,當你輸入一定的值得時候,結果就會出現以下結果:
Name:Beth Phone number(p) or address(a)?a Beth's address is Bar street 42
4.2.3將字串格式設定功能用於字典
在第三章,,我們都是使format方法通過命名或者非命名引數提供給方法format的,在字典中我們也能應用這種方法,下面舉兩個例子:
舉例:
phonebook={'Beth':'9102','Alice':'2341','Cecil':'3258'} print("Cecil's phone number is {Cecil}.".format_map(phonebook))
這個例子將會出現下面這樣的結果:
Cecil's phone number is 3258.
像這樣的字典,我們可以使用任意數量的字典轉換說明符,注意在這宣告條件:所有的欄位名都是包含在字典中的鍵。在模板系統中,這很有用,以HTML舉例說明。
template ='''<html> ...<head><title>{title}</title></head> ...<body> ...<h1>{title}</h1> ...<p>{text}</p> ...<body>''' data={'title':'My Home Page','text':'Welcome to my home Page'} print(template.format_map(data))
然後出來的效果是:
<html> ...<head><title>My Home Page</title></head> ...<body> ...<h1>My Home Page</h1> ...<p>Welcome to my home Page</p> ...<body>
4.2.4 字典方法
與其他內建型別一樣,字典也有方法。但沒有列表和字串的方法那樣高。大致瀏覽瞭解即可。
1.clear
方法clear刪除所有的字典項,這種操作是就地執行(就像list.sort一樣).因此什麼都不返回(或者說返回None)。
d={} d['name']='Gumby' d['age']= 42 print(d) returned_value =d.clear() print(d)
讓我們看看這個程式執行的結果,與我們預期是否一致:
{'name': 'Gumby', 'age': 42} {}
顯然是成立的,清空了所有的列表元素。那麼在那種場景能夠用到,下面我們來看看的這兩種情況:
x={} y = x x['key']='value' x={} print(x) print(y)
看看輸出的結果:
{} {'key': 'value'}
看看第二個例子:
x={} y=x x['key']='value' print(y) x.clear() print(y)
緊接著,我們看看第二個例子所得到的結果:
{'key': 'value'} {}
你會發現,y的值也被隨之清空,那麼,現在談一談我對這方面的理解,其實兩種情況都是x與y指向相同的字典,通過第一個空字典賦給x來清空‘它。這對於y沒影響,但用clear,y也將變為空,這個就是清除clear的所有內容。
2.copy和deepcopy
方法copy只是返回一個新的字典,其包含的鍵-值對於原本的字典相同(這種方法執行的是淺複製,因為值本身是原件,而非副本,但對於值為列表的時候,只是使它找到的地址相同,所以仍然在被修改的過程中都能夠修改)
x={'username':'admin','machines':['foo','bar','baz']} y=x.copy() y['username']='mlh' y['machines'].remove('baz') print(x) print(y)
結果可想而知:
{'username': 'admin', 'machines': ['foo', 'bar']} {'username': 'mlh', 'machines': ['foo', 'bar']
但深複製不太一樣,即它是複製值以及包含所有項的值甚至是他記錄地址的值也會被複制,下面舉個例子我們來比較一下:
from copy import deepcopy d={} d['name']=['Alfred','Bertrand'] c=d.copy() dc=deepcopy(d) d['name'].append('Clive') print(c) print(dc)
從而比較一下結果:
{'name': ['Alfred', 'Bertrand', 'Clive']} {'name': ['Alfred', 'Bertrand']}
3.fromkeys
方法fromkeys建立一個新的字典,包含指定的鍵且每個鍵的值都為None.
print({}.fromkeys(['name','age']))
得到的結果為:
print({}.fromkeys(['name','age']))
如果不想像上面那麼麻煩,則可以直接使用dict:
print(dict.fromkeys(['name','age']))
從而得到結果為:
{'name': None, 'age': None}
如果不想使用預設值,可指定預設值
print(dict.fromkeys(['name','age'],'(unknown)'))
從而得到結果為:
{'name': '(unknown)', 'age': '(unknown)'}
4.get
通常情況下,如果你試圖訪問字典沒有的項,會顯示錯誤:
d={} print(d['name'])
錯誤結果如下:
Traceback (most recent call last): File "G:/Py_project/Python基礎教程/字典.py", line 2, in <module> print(d['name']) KeyError: 'name'
但如果你使用get方法的情況下,就不會出現上述的問題,沒有引發異常,而是返回None,如果想返回你指定的內容,也可在get中自己設定:
d={} print(d.get('name'))
結果為:
None
如果是自己指定的返回值,即為如下程式碼:一個為輸入,一個為結果:
d={} print(d.get('name','N/A'))
N/A
這裡在舉一個簡單的字典的方法示例:
people={ 'Alice':{ 'phone':'2341', 'addr':'Foo drive 23' }, 'Beth':{ 'phone':'9102', 'addr':'bar street 42' }, 'Cecil':{ 'phone':'3158', 'addr':'Baz avenue 90' } } labels={ 'phone':'phone number', 'addr':'address' } name=input('name:') #要查詢電話號碼還是地址 request=input('Phobe number(p) or address(a)?') #使用正確的鍵 if request=='p': key='phone' if request=='a': key='addr' #使用get提供預設值 person=people.get(name,{}) label=labels.get(key,key) result=person.get(key,'not available') print("{}'s {} is {}".format(name,label,result))
從而能夠去驗證,驗證的結果下面:
name:Gumby Phobe number(p) or address(a)?p Gumby's phone number is not availed
5.items
方法items返回一個包含所有字典項的列表,其中每個元素都為(key,value)的形式(注意:排列順序不確定),形式如下:
d={'add':['hehe','haha'],'title':'Python Web Site','url':'http://www.python.org','spam':0} print(d.items())
這種形式會返回一種字典檢視,結果如下:
d={'add':['hehe','haha'],'title':'Python Web Site','url':'http://www.python.org','spam':0} print(d.items())
當然根據字典檢視,我們有一些相應的操作,比如可用於迭代(關於迭代在第五章節),另外,還可確定其長度以及執行成員資格檢查,下面就是關於這個的示例:
d={'title':'Python Web Site','url':'http://www.python.org','spam':0} it=d.items() print(len(it)) print(('spam',0) in it)
結果顯而易見:
3 True
注意:在文章中,提到了有意思的地方為:檢視不可複製,記住,不可以被複制,它只是作為底層字典的一種反映,修改底層的字典就能夠被反映出來:
d={'title':'Python Web Site','url':'http://www.python.org','spam':0} it=d.items() print(('spam',0) in it) d['spam']=1 print(('spam',0) in it) d['spam']=0 print(('spam',0) in it)
讓我們 來看看結果:
True False True
這的確印證了我們上面的注意項。當然,除了上面的功能,我們也同樣可以將字典檢視對映為列表:
d={'title':'Python Web Site','url':'http://www.python.org','spam':0} print(list(d.items()))
此時的結果為:
[('title', 'Python Web Site'), ('url', 'http://www.python.org'), ('spam', 0)]
6.keys
方法keys返回一個字典檢視,其中包含指定字典的鍵,舉個簡單的例子:
d={'title':'Python Web Site','url':'http://www.python.org','spam':0} print(d.keys())
本身就會返回一個字典檢視:
dict_keys(['title', 'url', 'spam'])
7.pop
方法pop用於刪除你指定鍵的值,從字典中刪除,舉例說明:
d={'x':1,'y':2} d.pop('x') print(d)
從而得到結果為:
{'y': 2}
8.popitem
popitem稱為隨機刪除,不指定鍵隨機刪除:
d={'x':1,'y':2} d.popitem() print(d)
檢視結果為:
{'x': 1}
9.setdefault
這個我剛問感覺很有用,有點像get,其實區別就是setdefault對於你指定的鍵,如果沒有,將其新增進入字典,並返回預設值給你,注意,如果你在setdefault裡面設定了預設值,返回你的,如果沒有,返回None;當然,如果有直接返回給你。舉個例子:
d={} print(d.setdefault('name','N/A')) print(d) d['name']='Gumby' print(d.setdefault('name','N/A'))
從而得到結果為:
N/A {'name': 'N/A'} Gumby
10.update
update的中文意思為更新,其實就是使用一個字典中的項去更新另外一個字典:
d={ 'title':'Python Web Site', 'url':'http://www.python.org', 'changed':'Mar 14 22:09:15 MET 2016' } x={'title':'Python Language Website'} d.update(x) print(d)
從而,得到下面的結果:
{'title': 'Python Language Website', 'url': 'http://www.python.org', 'changed': 'Mar 14 22:09:15 MET 2016'}
注意:通過引數提供的字典,將其項新增到當前的字典中。如果當前字典包含的鍵相同的值,就替換它。
本章節,我有一點不理解的地方就是:就是這個update的最後一句話:可像呼叫本章前面討論的函式dict(類似建構函式)那樣呼叫函式update。這意味著呼叫update時,可向它提供一個對映、一個由鍵-值對組成的序列(或者其他可迭代物件)或者關鍵字。
11.value
方法values返回一個由字典中的值組成的字典檢視。不同於方法keys,方法values返回的檢視可能包含重複的值。舉個例子進行說明:
d={} d[1]=1 d[2]=2 d[3]=3 d[4]=1 print(d)
然後在採用:
print(d.values())
最後得到結果為:
{1: 1, 2: 2, 3: 3, 4: 1} dict_values([1, 2, 3, 1])