字典,這個(gè)東西你現(xiàn)在還用嗎?隨著網(wǎng)絡(luò)的發(fā)展,用的人越來越少了。不少人習(xí)慣于在網(wǎng)上搜索,不僅有 web 版,乃至于已經(jīng)有手機(jī)版的各種字典了。我在上小學(xué)的時(shí)候曾經(jīng)用過一本小小的《新華字典》,記得是拾了不少廢品,然后換錢,最終花費(fèi)了 1.01 元人民幣買的。
《新華字典》是中國第一部現(xiàn)代漢語字典。最早的名字叫《伍記小字典》,但未能編纂完成。自 1953 年,開始重編,其凡例完全采用《伍記小字典》。從 1953 年開始出版,經(jīng)過反復(fù)修訂,但是以 1957 年商務(wù)印書館出版的《新華字典》作為第一版。原由新華辭書社編寫,1956 年并入中科院語言研究所(現(xiàn)中國社科院語言研究所)詞典編輯室。新華字典由商務(wù)印書館出版。歷經(jīng)幾代上百名專家學(xué)者 10 余次大規(guī)模的修訂,重印 200 多次。成為迄今為止世界出版史上最高發(fā)行量的字典。
這里講到字典,不是為了回憶青蔥歲月。而是提醒看官想想我們?nèi)绾问褂米值洌合炔樗饕ú还苁瞧匆暨€是偏旁查字),然后通過索引找到相應(yīng)內(nèi)容。不用從頭開始一頁一頁地找。
這種方法能夠快捷的找到目標(biāo)。
正是基于這種需要,Python 中有了一種叫做 dictionary 的數(shù)據(jù)類型,翻譯過來就是“字典”,用 dict 表示。
假設(shè)一種需要,要存儲城市和電話區(qū)號,蘇州的區(qū)號是 0512,唐山的是 0315,北京的是 011,上海的是 012。用前面已經(jīng)學(xué)習(xí)過的知識,可以這么來做:
>>> citys = ["suzhou", "tangshan", "beijing", "shanghai"]
>>> city_codes = ["0512", "0315", "011", "012"]
用一個(gè)列表來存儲城市名稱,然后用另外一個(gè)列表,一一對應(yīng)地保存區(qū)號。假如要輸出蘇州的區(qū)號,可以這么做:
>>> print "{} : {}".format(citys[0], city_codes[0])
suzhou : 0512
請?zhí)貏e注意,我在 city_codes 中,表示區(qū)號的元素沒有用整數(shù)型,而是使用了字符串類型,你知道為什么嗎? 如果用整數(shù),就是這樣的。
suzhou_code = 0512 print suzhou_code 330
怎么會這樣?原來在 Python 中,如果按照上面那樣做,0512 并沒有被認(rèn)為是一個(gè)八進(jìn)制的數(shù),用 print 打印的時(shí)候,將它轉(zhuǎn)換為了十進(jìn)制輸出。關(guān)于進(jìn)制轉(zhuǎn)換問題,看官可以網(wǎng)上搜索一下有關(guān)資料。此處不詳述。一般是用幾個(gè)內(nèi)建函數(shù)實(shí)現(xiàn):
int()
,bin()
,oct()
,hex()
這樣來看,用兩個(gè)列表分別來存儲城市和區(qū)號,似乎能夠解決問題。但是,這不是最好的選擇,至少在 Python 里面。因?yàn)?Python 還提供了另外一種方案,那就是字典(dict)。
方法 1:
創(chuàng)建一個(gè)空的 dict,這個(gè)空 dict,可以在以后向里面加?xùn)|西用。
>>> mydict = {}
>>> mydict
{}
不要小看“空”,“色即是空,空即是色”,在編程中,“空”是很重要。一般帶“空”字的人都很有名,比如孫悟空,哦。好像他應(yīng)該是猴、或者是神。舉一個(gè)人的名字,帶“空”字,你懂得。
創(chuàng)建有內(nèi)容的 dict。
>>> person = {"name":"qiwsir","site":"qiwsir.github.io","language":"python"}
>>> person
{'name': 'qiwsir', 'language': 'python', 'site': 'qiwsir.github.io'}
"name":"qiwsir"
,有一個(gè)優(yōu)雅的名字:鍵值對。前面的 name 叫做鍵(key),后面的 qiwsir 是前面的鍵所對應(yīng)的值(value)。在一個(gè) dict 中,鍵是唯一的,不能重復(fù)。值則是對應(yīng)于鍵,值可以重復(fù)。鍵值之間用(:)英文的分號,每一對鍵值之間用英文的逗號(,)隔開。
>>> person['name2']="qiwsir" #這是一種向 dict 中增加鍵值對的方法
>>> person
{'name2': 'qiwsir', 'name': 'qiwsir', 'language': 'Python', 'site': 'qiwsir.github.io'}
用這樣的方法可以向一個(gè) dict 類型的數(shù)據(jù)中增加“鍵值對”,也可以說是增加數(shù)值。那么,增加了值之后,那個(gè)字典還是原來的嗎?也就是也要同樣探討一下,字典是否能原地修改?(列表可以,所以列表是可變的;字符串和元組都不行,所以它們是不可變的。)
>>> ad = {}
>>> id(ad)
3072770636L
>>> ad["name"] = "qiwsir"
>>> ad
{'name': 'qiwsir'}
>>> id(ad)
3072770636L
實(shí)驗(yàn)表明,字典可以原地修改,即它是可變的。
方法 2:
利用元組在建構(gòu)字典,方法如下:
>>> name = (["first","Google"],["second","Yahoo"])
>>> website = dict(name)
>>> website
{'second': 'Yahoo', 'first': 'Google'}
或者用這樣的方法:
>>> ad = dict(name="qiwsir", age=42)
>>> ad
{'age': 42, 'name': 'qiwsir'}
方法 3:
這個(gè)方法,跟上面的不同在于使用 fromkeys
>>> website = {}.fromkeys(("third","forth"),"facebook")
>>> website
{'forth': 'facebook', 'third': 'facebook'}
需要提醒的是,這種方法是重新建立一個(gè) dict。
需要提醒注意的是,在字典中的“鍵”,必須是不可變的數(shù)據(jù)類型;“值”可以是任意數(shù)據(jù)類型。
>>> dd = {(1,2):1}
>>> dd
{(1, 2): 1}
>>> dd = {[1,2]:1}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
dict 數(shù)據(jù)類型是以鍵值對的形式存儲數(shù)據(jù)的,所以,只要知道鍵,就能得到值。這本質(zhì)上就是一種映射關(guān)系。
映射,就好比“物體”和“影子”的關(guān)系,“形影相吊”,兩者之間是映射關(guān)系。此外,映射也是一個(gè)嚴(yán)格數(shù)學(xué)概念:A 是非空集合,A 到 B 的映射是指:A 中每個(gè)元素都對應(yīng)到 B 中的某個(gè)元素。
既然是映射,就可以通過字典的“鍵”找到相應(yīng)的“值”。
>>> person
{'name2': 'qiwsir', 'name': 'qiwsir', 'language': 'python', 'site': 'qiwsir.github.io'}
>>> person['name']
'qiwsir'
>>> person['language']
'python'
如同前面所講,通過“鍵”能夠增加 dict 中的“值”,通過“鍵”能夠改變 dict 中的“值”,通過“鍵”也能夠訪問 dict 中的“值”。
本節(jié)開頭那個(gè)城市和區(qū)號的關(guān)系,也可以用字典來存儲和讀取。
>>> city_code = {"suzhou":"0512", "tangshan":"0315", "beijing":"011", "shanghai":"012"}
>>> print city_code["suzhou"]
0512
既然 dict 是鍵值對的映射,就不用考慮所謂“排序”問題了,只要通過鍵就能找到值,至于這個(gè)鍵值對位置在哪里就不用考慮了。比如,剛才建立的 city_code
>>> city_code
{'suzhou': '0512', 'beijing': '011', 'shanghai': '012', 'tangshan': '0315'}
雖然這里顯示的和剛剛賦值的時(shí)候順序有別,但是不影響讀取其中的值。
在 list 中,得到值是用索引的方法。那么在字典中有索引嗎?當(dāng)然沒有,因?yàn)樗鼪]有順序,哪里來的索引呢?所以,在字典中就不要什么索引和切片了。
dict 中的這類以鍵值對的映射方式存儲數(shù)據(jù),是一種非常高效的方法,比如要讀取值得時(shí)候,如果用列表,Python 需要從頭開始讀,直到找到指定的那個(gè)索引值。但是,在 dict 中是通過“鍵”來得到值。要高效得多。 正是這個(gè)特點(diǎn),鍵值對這樣的形式可以用來存儲大規(guī)模的數(shù)據(jù),因?yàn)闄z索快捷。規(guī)模越大越明顯。所以,mongdb 這種非關(guān)系型數(shù)據(jù)庫在大數(shù)據(jù)方面比較流行了。
字典雖然跟列表有很大的區(qū)別,但是依然有不少類似的地方。它的基本操作:
下面依次進(jìn)行演示。
>>> city_code
{'suzhou': '0512', 'beijing': '011', 'shanghai': '012', 'tangshan': '0315'}
>>> len(city_code)
4
以 city_code 為操作對象,len(city_code)的值是 4,表明有四組鍵值對,也可以說是四項(xiàng)。
>>> city_code["nanjing"] = "025"
>>> city_code
{'suzhou': '0512', 'beijing': '011', 'shanghai': '012', 'tangshan': '0315', 'nanjing': '025'}
向其中增加一項(xiàng)
>>> city_code["beijing"] = "010"
>>> city_code
{'suzhou': '0512', 'beijing': '010', 'shanghai': '012', 'tangshan': '0315', 'nanjing': '025'}
突然發(fā)現(xiàn)北京的區(qū)號寫錯(cuò)了??梢赃@樣修改。這進(jìn)一步說明字典是可變的。
>>> city_code["shanghai"]
'012'
>>> del city_code["shanghai"]
通過 city_code["shanghai"]
能夠查看到該鍵(key)所對應(yīng)的值(value),結(jié)果發(fā)現(xiàn)也錯(cuò)了。干脆刪除,用 del,將那一項(xiàng)都刪掉。
>>> city_code["shanghai"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'shanghai'
>>> "shanghai" in city_code
False
因?yàn)殒I是"shanghai"的那個(gè)鍵值對項(xiàng)已經(jīng)刪除了,隨意不能找到,用 in
來看看,返回的是 False
。
>>> city_code
{'suzhou': '0512', 'beijing': '010', 'tangshan': '0315', 'nanjing': '025'}
真的刪除了哦。沒有了。
這是一個(gè)前面已經(jīng)探討過的話題,請參看《字符串(4)》,這里再次提到,就是因?yàn)橛米值湟部梢詫?shí)現(xiàn)格式化字符串的目的。雖然在《字符串(4)》那節(jié)中已經(jīng)有了簡單演示,但是我還是愿意重復(fù)一下。
>>> city_code = {"suzhou":"0512", "tangshan":"0315", "hangzhou":"0571"}
>>> " Suzhou is a beautiful city, its area code is %(suzhou)s" % city_code
' Suzhou is a beautiful city, its area code is 0512'
這種寫法是非常簡潔,而且很有意思的。有人說它簡直是酷。
其實(shí),更酷還是下面的——模板
在做網(wǎng)頁開發(fā)的時(shí)候,通常要用到模板,也就是你只需要寫好 HTML 代碼,然后將某些部位空出來,等著 Python 后臺提供相應(yīng)的數(shù)據(jù)即可。當(dāng)然,下面所演示的是玩具代碼,基本沒有什么使用價(jià)值,因?yàn)樵谡鎸?shí)的網(wǎng)站開發(fā)中,這樣的姿勢很少用上。但是,它絕非花拳繡腿,而是你能夠明了其本質(zhì),至少了解到一種格式化方法的應(yīng)用。
>>> temp = "<html><head><title>%(lang)s<title><body><p>My name is %(name)s.</p></body></head></html>"
>>> my = {"name":"qiwsir", "lang":"python"}
>>> temp % my
'<html><head><title>python<title><body><p>My name is qiwsir.</p></body></head></html>'
temp 就是所謂的模板,在雙引號所包裹的實(shí)質(zhì)上是一段 HTML 代碼。然后在 dict 中寫好一些數(shù)據(jù),按照模板的要求在相應(yīng)位置顯示對應(yīng)的數(shù)據(jù)。
是不是一個(gè)很有意思的屠龍之技?
什么是 HTML? 下面是在《維基百科》上抄錄的:
超文本標(biāo)記語言(英文:HyperText Markup Language,HTML)是為「網(wǎng)頁創(chuàng)建和其它可在網(wǎng)頁瀏覽器中看到的信息」設(shè)計(jì)的一種標(biāo)記語言。HTML 被用來結(jié)構(gòu)化信息——例如標(biāo)題、段落和列表等等,也可用來在一定程度上描述文檔的外觀和語義。1982 年由蒂姆·伯納斯-李創(chuàng)建,由 IETF 用簡化的 SGML(標(biāo)準(zhǔn)通用標(biāo)記語言)語法進(jìn)行進(jìn)一步發(fā)展的 HTML,后來成為國際標(biāo)準(zhǔn),由萬維網(wǎng)聯(lián)盟(W3C)維護(hù)。
HTML 經(jīng)過發(fā)展,現(xiàn)在已經(jīng)到 HTML5 了?,F(xiàn)在的 HTML 設(shè)計(jì),更強(qiáng)調(diào)“響應(yīng)式”設(shè)計(jì),就是能夠兼顧 PC、手機(jī)和各種 PAD 的不同尺寸的顯示器瀏覽。如果要開發(fā)一個(gè)網(wǎng)站,一定要做到“響應(yīng)式”設(shè)計(jì),否則就只能在 PC 上看,在手機(jī)上看就不得不左右移動。
什么是關(guān)聯(lián)數(shù)組?以下解釋來自維基百科
在計(jì)算機(jī)科學(xué)中,關(guān)聯(lián)數(shù)組(英語:Associative Array),又稱映射(Map)、字典(Dictionary)是一個(gè)抽象的數(shù)據(jù)結(jié)構(gòu),它包含著類似于(鍵,值)的有序?qū)?。一個(gè)關(guān)聯(lián)數(shù)組中的有序?qū)梢灾貜?fù)(如 C++ 中的 multimap)也可以不重復(fù)(如 C++ 中的 map)。
這種數(shù)據(jù)結(jié)構(gòu)包含以下幾種常見的操作:
- 向關(guān)聯(lián)數(shù)組添加配對
- 從關(guān)聯(lián)數(shù)組內(nèi)刪除配對
- 修改關(guān)聯(lián)數(shù)組內(nèi)的配對
- 根據(jù)已知的鍵尋找配對
字典問題是設(shè)計(jì)一種能夠具備關(guān)聯(lián)數(shù)組特性的數(shù)據(jù)結(jié)構(gòu)。解決字典問題的常用方法,是利用散列表,但有些情況下,也可以直接使用有地址的數(shù)組,或二叉樹,和其他結(jié)構(gòu)。
許多程序設(shè)計(jì)語言內(nèi)置基本的數(shù)據(jù)類型,提供對關(guān)聯(lián)數(shù)組的支持。而 Content-addressable memory 則是硬件層面上實(shí)現(xiàn)對關(guān)聯(lián)數(shù)組的支持。
什么是哈希表?關(guān)于哈希表的敘述比較多,這里僅僅截取了概念描述,更多的可以到維基百科上閱讀。
散列表(Hash table,也叫哈希表),是根據(jù)關(guān)鍵字(Key value)而直接訪問在內(nèi)存存儲位置的數(shù)據(jù)結(jié)構(gòu)。也就是說,它通過把鍵值通過一個(gè)函數(shù)的計(jì)算,映射到表中一個(gè)位置來訪問記錄,這加快了查找速度。這個(gè)映射函數(shù)稱做散列函數(shù),存放記錄的數(shù)組稱做散列表。
總目錄 | 上節(jié):元組 | 下節(jié):字典(2)
如果你認(rèn)為有必要打賞我,請通過支付寶:qiwsir@126.com,不勝感激。