數據字典
字典(dictionary)是除列表之外python之中最靈活的內置數據結構類型。列表是有序的對象結合,字典是無序的對象集合。兩者之間的區別在於:字典當中的元素是通過鍵來存取的,而不是通過偏移存取,這個鍵可以是數字、字符串甚至元組。映射可以使用任何不可變對象標識元素,最常用的類型是字符串和元組,python唯一內建的映射類型是字典。
創建和使用字典:
>>> phonebook={'Jason':'23453','James':'34231','Jzhou':'90798'} >>> phonebook['Jason'] '23453'
字典由多個鍵和其對應的值構成的對組成(鍵值對稱為項),上例中,姓名是鍵,分機號是值。每個鍵和它的值之間用冒號隔開,項之間用逗號隔開,整個字典用一對大括號括起來。
(注意:字典中的鍵是唯一的,其它映射也是如此,而值不唯一)
dict函數
dict函數可以通過其他映射(比如其他字典)或者(鍵、值)這樣的序列對建立字典
>>> items=[('name','Gumby'),('age',42)] >>> d=dict (items ) >>> d {'age': 42, 'name': 'Gumby'} >>> d['name'] 'Gumby'
dict函數也可以通過關鍵字參數來創建字典
>>> d=dict(name='Jason',age=42) >>> d {'age': 42, 'name': 'Jason'}
還能以映射作為dict函數的參數,以建立其項與映射相同的字典,如果不帶任何參數,則dict函數返回一個新的空的字典,就行list,tuple,str等函數一樣。如果另一個映射也是字典,可以使用字典方法copy(之后介紹)。
基本的字典操作
字典的基本行為在很多方面和序列類似:
len(d) 返回d中項(鍵-值對)的數量
d[k]返回關聯到鍵k上的值
d[k]=v 將值v關聯到鍵k上
del d[k]刪除鍵為k的項
k in d 檢查中是否有含有鍵為k的項
字典也有一些自己的特性,如下:
鍵類型:字典的鍵不一定為整型數據,也可能是其他不可變類型,如浮點型、字符串、元組等
自動添加:即使那個鍵起初不存在於字典中,也可以分配給它一個值,即字典會建立一個新項;而列表在不使用append方法的前提下,不能將值關聯到列表之外的索引上
成員資格:表達式k in d(d為字典)查找的是鍵而不是值;表達式 v in l(l為列表)則用來查找值,而不是索引(另外,在字典中檢查鍵的成員資格比在列表中檢查值的成員更高效,尤其當數據結構的規模很大時。)
我們來看一個簡單的例子,來看看字典相對於列表的好處:
>>> x=[] #創建一個空列表 >>> x[42]='floor' #出現錯誤 Traceback (most recent call last): File "<pyshell#77>", line 1, in <module> x[42]='floor' IndexError: list assignment index out of range >>> x={} #創建一個字典 >>> x[42]='floor' #自動將這項添加到字典中 >>> x #字典的值 {42: 'floor'} >>>
下面是一個較復雜的字典的示例:
# 使用人名作為鍵的字典,每個人用另一個字典來表示,phone和addr是子字典的鍵 people ={ 'Jason':{ 'phone':'2341', 'addr':'Foo drive 23' }, 'James':{ 'phone':'4564', 'addr':'Bar street 42' }, 'Jzhou':{ 'phone':'4564', 'addr':'Baz avenue 90' } } # 針對電話號碼和地址使用的描述性標簽會在打印輸出的時候用到 labels={ 'phone':'phone number', 'addr':'address' } name=raw_input('Name:') # 查找電話號碼還是地址?使用正確的鍵 request=raw_input ("Phone number(p) or address(a)?") # 使用正確的鍵: if request=='p':key='phone' if request=='a':key='addr' # 如果名字是字典中的有效鍵才打印信息 if name in people: print "%s's %s is %s." % (name,labels[key],people[name][key]) raw_input("press any key to exit!")
運行結果如下:
字典的格式化字符串
上一篇介紹過字符串是如何格式化的,現在我們來看看字典是如何格式化的。在每個轉換說明符的后面,加上鍵再跟其他說明元素。看例子:
>>> phonebook={'James':'3422','Jason':'3441','Jzhou':'2321'} >>> phonebook {'James': '3422', 'Jason': '3441', 'Jzhou': '2321'} >>> "Jzhou's phone number is %(Jzhou)s." % phonebook "Jzhou's phone number is 2321."
除了增加字符串鍵之外,轉換說明符還是像以前一樣,當以這種方式使用字典的時候,只要所有給出的鍵都能在字典中找到,就可以獲得任意數量的轉換說明符,所以這類字符串格式化在模板系統中非常有用,看下面這個例子:
>>> template='''<html> <head><title>%(title)s</title></head> <body> <h1>%(title)s<h1> <p>%(text)s</p> </body>''' >>> data={'title':'my home page','text':'Welcome to my home age!'} >>> print template % data <html> <head><title>my home page</title></head> <body> <h1>my home page<h1> <p>Welcome to my home age!</p> </body>
字典方法
clear——清除字典中的所有項。類似於list.sort,無返回值
>>> d={} >>> d['name']='Jason' >>> d['age']=42 >>> d {'age': 42, 'name': 'Jason'} >>> return_value=d.clear() >>> d {} >>> print return_value None
通過下面的例子看一下clear的簡單作用:
#未使用clear方法 >>> x={} >>> y=x >>> x['key']='value' >>> y {'key': 'value'} >>> x={} >>> y #x使用x={}置空后y的值還存在 {'key': 'value'} #使用clear方法 >>> x={} >>> y=x >>> x['key']='value' >>> y {'key': 'value'} >>> x.clear() #x使用clear方法后,y的值也被清空了 >>> y {}
copy——返回一個具有相同鍵值對的新字典(實現的是淺復制,因為值本身相同,而不是副本)
>>> x={'username':'admin','machines':['foo','bar','baz']} >>> y=x.copy() >>> y['username']='mlh' >>> y['machines'].remove ('bar') >>> y {'username': 'mlh', 'machines': ['foo', 'baz']} >>> x {'username': 'admin', 'machines': ['foo', 'baz']}
上例看出,當在副本中替換值的時候,原字典不受影響,想上述y中username賦了新值,而x沒變;但是如果修改了某個值而不是替換,則原字典也會改變,像上述y的machines中移除了bar,則x中也移除了這個值。
避免這個問題的方法是使用深復制(deep copy),復制它包含所有的值。使用copy模塊的deepcopy函數來完成
>>> from copy import deepcopy >>> d={} >>> d['names']=['James','Jason'] >>> c=d.copy() >>> dc=deepcopy(d) >>> d['names'].append('Jzhou') >>> c {'names': ['James', 'Jason', 'Jzhou']} >>> dc {'names': ['James', 'Jason']}
fromkeys——使用給定的鍵建立新的字典,每個鍵默認對應的值為None
>>> {}.fromkeys(['name','age']) #構造了有一個空字典來建立另外一個字典 {'age': None, 'name': None}
也可以直接在所有字典的類型dict上調用方法
>>> dict.fromkeys(['name','age']) {'age': None, 'name': None}
若不想使用None作默認值,也可以提供自己的默認值
>>> dict.fromkeys(['name','age'],'Unknown') {'age': 'Unknown', 'name': 'Unknown'}
get——得到字典中的某個項
#一般當是視圖得到字典中不存在的項時將出錯 >>> d={} >>> print d['name'] Traceback (most recent call last): File "<pyshell#42>", line 1, in <module> print d['name'] KeyError: 'name' #使用get方法時不會出錯 >>> print d.get('name') None #也可以自定義默認值來替換'None' >>> d.get('name','N/A') 'N/A' #如果鍵值存在,get用起來就像普通的字典查詢一樣 >>> d['name']='Eric' >>> d.get('name') 'Eric'
看下面這個經過改造的例子:
people ={ 'Jason':{ 'phone':'2341', 'addr':'Foo drive 23' }, 'James':{ 'phone':'4564', 'addr':'Bar street 42' } } labels={ 'phone':'phone number', 'addr':'address' } name = raw_input('Name:') #查找電話號碼還是地址? request=raw_input('phone number(p) or address(a)?') #使用正確的鍵 key=request if request =='p':key='phone' if request =='a':key='addr' person=people.get(name,{}) label=labels.get(key,key) #使用get()提供的默認值 result=person.get('key','not available') #如果請求不是p或者a,則使用get()提供的默認值 if request != 'p' and request != 'a': print "%s's %s is %s." % (name,label,result) #如果請求正確,則按正常處理 elif request == 'p' or request == 'a': print "%s's %s is %s." % (name,labels[key],people[name][key]) raw_input("press any key to exit!")
運行結果如下,即正常輸入和異常輸入時的處理結果:
has_key——檢查字典中是否含有給出的鍵。表達式dict.has_key(k)相當於 表達式key in dict。注意在python3.0中不包含這個函數了。
>>> d={} >>> d.has_key('name') False >>> d['name']='Jzhou' >>> d.has_key('name') True
items和iteritems——items方法將所有字典項以列表方式返回,這些列表項中的每一項都來自於(鍵、值),但是在項返回時並沒有特殊順序。
>>> d={'title':'python','url':'http://www.python.org'}
>>> d.items ()
[('url', 'http://www.python.org'), ('title', 'python')]
iteritems作用大致一樣,但是會返回一個迭代器對象而不是列表
>>> it=d.iteritems () >>> it <dictionary-itemiterator object at 0x01D9EAB0> >>> list(it) #將iterator轉換為列表 [('url', 'http://www.python.org'), ('title', 'python')]
keys和iterkeys——keys方法將字典中的鍵以列表的形式返回,而iterkeys是返回針對鍵的迭代器
>>> d.keys() ['url', 'title'] >>> d.iterkeys() <dictionary-keyiterator object at 0x02BD1DE0> >>> list(d.iterkeys ()) ['url', 'title']
values和itervalues——values方法以列表的形式返回字典中的值,itervalues返回值的迭代器。與返回鍵的列表不同的是,返回值的列表中可以包含重復的元素
>>> d={} >>> d[1]=1 >>> d[2]=2 >>> d[3]=3 >>> d[4]=1 >>> d.values() [1, 2, 3, 1] >>> d.itervalues () <dictionary-valueiterator object at 0x02BD1ED0> >>> list(d.itervalues ()) [1, 2, 3, 1]
pop——獲得對應於給定鍵的值,然后將這個鍵值對從字典中移除
>>> d={'x':1,'y':2} >>> d.pop('x') 1 >>> d {'y': 2}
popitem——類似list.pop,后者會彈出列表的最后一個元素,但不同的是,popitem彈出的是隨機的項,因為字典是無序的。若想一個接一個的移除並處理項,這個方法非常有效,因為不用先獲取鍵的列表
>>> d={'title':'python','url':'http://www.python.org','spam':0} >>> d {'url': 'http://www.python.org', 'spam': 0, 'title': 'python'} >>> d.popitem() ('url', 'http://www.python.org') >>> d {'spam': 0, 'title': 'python'}
盡管popitem和列表的pop方法很類似,但字典中並沒有與append等價的方法,因為字典是無序的,無“追加至最后”可言。
setdefault——獲得與給定鍵相關聯的值,類似get()方法,另外,它還能在字典中不含有給定鍵的情況下設定相應的鍵值
>>> d={} >>> d.setdefault('name','N/A') 'N/A' >>> d {'name': 'N/A'} >>> d['name']='Jzhou' >>> d.setdefault('name','N/A') 'Jzhou' >>> d {'name': 'Jzhou'}
可以看出,當鍵不存在的時候,setdefault返回默認值並且相應的更新字典。如果鍵存在,那么就返回與其對應的值,但不改變字典。默認值可選,如果不寫,默認為None
>>> d={} >>> print d.setdefault('name') None >>> d {'name': None}
update——利用一個字典更新另外一個字典
>>> d={ 'title':'Python web site', 'url':'http://www.python.org', 'changed':'April 4 20:18 2013' } >>> x={'title':'Python Language Website'} >>> d.update(x) #提供的字典中的項會被添加到舊的字典中,若有相同的鍵則會進行覆蓋 >>> d {'url': 'http://www.python.org', 'changed': 'April 4 20:18 2013', 'title': 'Python Language Website'}
以上是字典常用的主要方法,調用方式和調用列表及字符串的方式相同。