官术网_书友最值得收藏!

第7章 字典和集合

7.1 字典:當(dāng)索引不好用時(shí)

視頻講解

圖7-1 映射

有一天你想翻開《新華字典》,查找一下“龜”是不是一種鳥。如果是按拼音檢索,你總不可能從字母a開始查找吧?而應(yīng)該直接翻到字母g在字典中的位置,然后接著找到gui的發(fā)音,繼而找到“龜”字的釋義:廣義上指龜鱉目的統(tǒng)稱,狹義上指龜科下的物種。

在Python中也有字典,就拿剛才的例子來說,Python的字典把這個(gè)字(或單詞)稱為“鍵(key)”,把其對(duì)應(yīng)的含義稱為“值(value)”。另外值得一提的是,Python的字典在有些地方稱為哈希(hash),有些地方稱為關(guān)系數(shù)組,其實(shí)這些都與今天要講的Python字典是同一個(gè)概念。

字典是Python中唯一的映射類型,映射是數(shù)學(xué)上的一個(gè)術(shù)語,指兩個(gè)元素集之間元素相互“對(duì)應(yīng)”的關(guān)系,如圖7-1所示。

映射類型區(qū)別于序列類型,序列類型以數(shù)組的形式存儲(chǔ),通過索引的方式來獲取相應(yīng)位置的值,一般索引值與對(duì)應(yīng)位置存儲(chǔ)的數(shù)據(jù)是毫無關(guān)系的。

舉個(gè)例子:

     >>> brand = ["李寧", "耐克", "阿迪達(dá)斯", "魚C工作室"]
     >>> slogan = ["一切皆有可能", "Just do it", "Impossible is nothing", "讓
     編程改變世界"]
     >>> print("魚C工作室的口號(hào)是:%s" % slogan[brand.index("魚C工作室")])
     魚C工作室的口號(hào)是:讓編程改變世界

列表brand、slogan的索引和相對(duì)的值是沒有任何關(guān)系的,可以看出,在兩個(gè)列表間,索引號(hào)相同的元素是有關(guān)系的(品牌對(duì)應(yīng)口號(hào)),所以這里通過“brand.index('魚C工作室')”這樣的語句,間接地實(shí)現(xiàn)通過品牌查找對(duì)應(yīng)的口號(hào)的功能。

這確實(shí)是一種可實(shí)現(xiàn)方法,但用起來多少有些別扭,而且效率還不高。況且Python是以簡潔為主,這樣的實(shí)現(xiàn)肯定是差強(qiáng)人意的。

7.1.1 創(chuàng)建和訪問字典

先演示一下用法:

字典的使用非常簡單,它有自己的標(biāo)志性符號(hào),就是用大括號(hào)({})定義。字典由“鍵”和“值”共同構(gòu)成,每一對(duì)鍵值組合稱為“項(xiàng)”。

在剛才的例子中,李寧、耐克、阿迪達(dá)斯、魚C工作室這些品牌就是鍵,而一切皆有可能、Just do it、Impossible is nothing、讓編程改變世界,這些口號(hào)就是對(duì)應(yīng)的值。

注意:

字典的鍵必須獨(dú)一無二,但值則不必。值可以取任何數(shù)據(jù)類型,但必須是不可變的,如字符串、數(shù)或元組。

要聲明一個(gè)空字典,直接用大括號(hào)即可:

     >>> empty = {}
     >>> empty
     {}
     >>> type(empty)
     <class 'dict'>

也可以使用dict()內(nèi)置函數(shù)來創(chuàng)建字典:

     >>> dict1 = dict((('F', 70), ('i', 105), ('s', 115), ('h', 104), ('C', 67)))
     >>> dict1
     {'F': 70, 'i': 105, 's': 115, 'h': 104, 'C': 67}

有讀者可能會(huì)問,為什么上面的例子中出現(xiàn)這么多小括號(hào)?

因?yàn)閐ict()函數(shù)的參數(shù)可以是一個(gè)序列(但不能是多個(gè)),所以要打包成一個(gè)元組(或列表)序列。

當(dāng)然,如果嫌上面的做法太麻煩,還可以通過提供具有映射關(guān)系的參數(shù)來創(chuàng)建字典:

     >>> dict1 = dict(F=70, i=105, s=115, h=104, C=67)
     >>> dict1
     {'F': 70, 'i': 105, 's': 115, 'h': 104, 'C': 67}

這里要注意的是,鍵的位置不能加上表示字符串的引號(hào),否則會(huì)報(bào)錯(cuò):

     >>> dict1 = dict('F'=70, 'i'=105, 's'=115, 'h'=104, 'C'=67)
     SyntaxError: keyword can't be an expression

訪問字典里的值與訪問序列類似,只需要把相應(yīng)的鍵放入方括號(hào)即可,如果該鍵不在映射中,則拋出KeyError:

還有一種創(chuàng)建方法是直接給字典的鍵賦值,如果鍵已存在,則改寫鍵對(duì)應(yīng)的值;如果鍵不存在,則創(chuàng)建一個(gè)新的鍵并賦值:

     >>> dict1
     {'F': 70, 'i': 105, 's': 115, 'h': 104, 'C': 67}
     >>> dict1['x'] = 88
     >>> dict1
     {'F': 70, 'i': 105, 's': 115, 'h': 104, 'C': 67, 'x': 88}
     >>> dict1['x'] = 120
     >>> dict1
     {'F': 70, 'i': 105, 's': 115, 'h': 104, 'C': 67, 'x': 120}

注意:

字典不允許同一個(gè)鍵出現(xiàn)兩次,如果同一個(gè)鍵被賦值兩次,后一個(gè)值會(huì)被記住:

     >>> courses = {"小甲魚":"《零基礎(chǔ)入門學(xué)習(xí)Python》", "不二如是":"《零基礎(chǔ)入門學(xué)
     習(xí)Scratch》", "小甲魚":"《極客Python之效率革命》"}
     >>> courses
     {'小甲魚': '《極客Python之效率革命》','不二如是': '《零基礎(chǔ)入門學(xué)習(xí)Scratch》'}

鍵必須不可變,所以可以用數(shù)值、字符串或元組充當(dāng),如果使用列表那就不行了:

正所謂殊途同歸,下面列舉的五種方法都是創(chuàng)建同樣的字典,大家仔細(xì)體會(huì)一下:

     >>> a = dict(one=1, two=2, three=3)
     >>> b = {'one': 1, 'two': 2, 'three': 3}
     >>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
     >>> d = dict([('two', 2), ('one', 1), ('three', 3)])
     >>> e = dict({'three': 3, 'one': 1, 'two': 2})
     >>> a == b == c == d == e
     True

有別于序列,字典是不支持拼接和重復(fù)操作的:

7.1.2 各種內(nèi)置方法

視頻講解

1)fromkeys(seq[, value])

fromkeys()方法用于創(chuàng)建并返回一個(gè)新的字典,它有兩個(gè)參數(shù);第一個(gè)參數(shù)是字典的鍵;第二個(gè)參數(shù)是可選的,是傳入鍵對(duì)應(yīng)的值,如果不提供,那么默認(rèn)是None。

舉個(gè)例子:

     >>> dict1 = {}
     >>> dict1.fromkeys((1, 2, 3))
     {1: None, 2: None, 3: None}
     >>> dict2 = {}
     >>> dict2.fromkeys((1, 2, 3), "Number")
     {1: 'Number', 2: 'Number', 3: 'Number'}
     >>> dict3 = {}
     >>> dict3.fromkeys((1, 2, 3), ("one", "two", "three"))
     {1: ('one', 'two', 'three'), 2: ('one', 'two', 'three'), 3: ('one', 'two',
     'three')}

上面最后一個(gè)例子告訴我們做事不能總是想當(dāng)然,有時(shí)候現(xiàn)實(shí)會(huì)給你狠狠的一棒。fromkeys()方法并不會(huì)將值"one"、"two"和"three"分別賦值鍵1、2和3,因?yàn)閒romkeys()把("one", "two", "three")當(dāng)成一個(gè)值了。

2)keys(),values()和items()

訪問字典的方法有keys()、values()和items()。keys()用于返回字典中的鍵,values()用于返回字典中所有的值,那么,items()當(dāng)然就是返回字典中所有的鍵值對(duì)(也就是項(xiàng))。

舉個(gè)例子:

     >>> dict1 = {}
     >>> dict1 = dict1.fromkeys(range(32), "贊")
     >>> dict1.keys()
     dict_keys([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31])
     >>> dict1.values()
     dict_values(['贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊',
     '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊',
     '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊'])
     >>> dict1.items()
     dict_items([(0, '贊'), (1, '贊'), (2, '贊'), (3, '贊'), (4, '贊'), (5,
     '贊'), (6, '贊'), (7, '贊'), (8, '贊'), (9, '贊'), (10, '贊'), (11, '贊'),
     (12, '贊'), (13, '贊'), (14, '贊'), (15, '贊'), (16, '贊'), (17, '贊'), (18,
     '贊'), (19, '贊'), (20, '贊'), (21, '贊'), (22, '贊'), (23, '贊'), (24,
     '贊'), (25, '贊'), (26, '贊'), (27, '贊'), (28, '贊'), (29, '贊'), (30,
     '贊'), (31, '贊')])

字典可以很大,有時(shí)候我們并不知道提供的項(xiàng)是否在字典中存在,如果不存在,Python就會(huì)報(bào)錯(cuò):

對(duì)于代碼調(diào)試階段,報(bào)錯(cuò)可以讓程序員及時(shí)發(fā)現(xiàn)程序存在的問題并修改。但是如果程序已經(jīng)發(fā)布了,那么經(jīng)常報(bào)錯(cuò)的程序肯定是會(huì)被用戶遺棄的。

3)get(key[, default])

get()方法提供了更寬松的方式去訪問字典項(xiàng),當(dāng)鍵不存在的時(shí)候,get()方法并不會(huì)報(bào)錯(cuò),只是默默地返回了一個(gè)None,表示啥都沒找到:

     >>> dict1.get(31)
     '贊'
     >>> dict1.get(32)
     >>>

如果希望找不到數(shù)據(jù)時(shí)返回指定的值,那么可以在第二個(gè)參數(shù)設(shè)置對(duì)應(yīng)的默認(rèn)返回值:

     >>> dict1.get(32, "木有")
     '木有'

如果不知道一個(gè)鍵是否在字典中,那么可以使用成員資格操作符(in或not in)來判斷:

     >>> 31 in dict1
     True
     >>> 32 in dict2
     False

在字典中檢查鍵的成員資格比序列更高效,當(dāng)數(shù)據(jù)規(guī)模相當(dāng)大的時(shí)候,兩者的差距會(huì)很明顯(注:因?yàn)樽值涫遣捎霉7椒ㄒ粚?duì)一找到成員,而序列則是采取迭代的方式逐個(gè)比對(duì))。最后要注意的一點(diǎn)是,這里查找的是鍵而不是值,但是在序列中查找的是元素的值而不是元素的索引。

如果需要清空一個(gè)字典,則使用clear()方法:

     >>> dict1
     {0: '贊', 1: '贊', 2: '贊', 3: '贊', 4: '贊', 5: '贊', 6: '贊', 7: '贊', 8:
     '贊', 9: '贊', 10: '贊', 11: '贊', 12: '贊', 13: '贊', 14: '贊', 15: '贊',
      16: '贊', 17: '贊', 18: '贊', 19: '贊', 20: '贊', 21: '贊', 22: '贊', 23:
     '贊', 24: '贊', 25: '贊', 26: '贊', 27: '贊', 28: '贊', 29: '贊', 30: '贊',
     31: '贊'}
     >>> dict1.clear()
     >>> dict1
     {}

有的讀者可能會(huì)使用變量名賦值為一個(gè)空字典的方法來清空字典,這樣的做法其實(shí)存在一定的弊端。

下面給大家解釋這兩種清除方法有什么不同。

     >>> a = {"姓名":"小甲魚", "密碼":"123456"}
     >>> b = a
     >>> b
     {'姓名': '小甲魚', '密碼': '123456'}
     >>> a = {}
     >>> a
     {}
     >>> b
     {'姓名': '小甲魚', '密碼': '123456'}

從上面的例子中可以看到,a、b指向同一個(gè)字典,然后試圖通過將a重新指向一個(gè)空字典來達(dá)到清空的效果時(shí),我們發(fā)現(xiàn)原來的字典并沒有被真正清空,只是a指向了一個(gè)新的空字典而已。所以,這種做法在一定條件下會(huì)留下安全隱患(例如,賬戶的數(shù)據(jù)和密碼等資料有可能會(huì)被竊取)。

推薦的做法是使用clear()方法:

     >>> a = {"姓名":"小甲魚", "密碼":"123456"}
     >>> b = a
     >>> b
     {'姓名': '小甲魚', '密碼': '123456'}
     >>> a.clear()
     >>> a
     {}
     >>> b
     {}

4)copy()

copy()方法是用于拷貝(淺拷貝)整個(gè)字典:

     >>> a = {1:"one", 2:"two", 3:"three"}
     >>> b = a.copy()
     >>> id(a)
     63239624
     >>> id(b)
     63239688
     >>> a[1] = "four"
     >>> a
     {1: 'four', 2: 'two', 3: 'three'}
     >>> b
     {1: 'one', 2: 'two', 3: 'three'}

5)pop(key[, default])和popitem()

pop()是給定鍵彈出對(duì)應(yīng)的值,而popitem()是彈出一個(gè)項(xiàng),這兩個(gè)比較容易理解:

     >>> a = {1:"one", 2:"two", 3:"three", 4:"four"}
     >>> a.pop(2)
     'two'
     >>> a
     {1: 'one', 3: 'three', 4: 'four'}
     >>> a.popitem()
     (1, 'one')
     >>> a
     {3: 'three', 4: 'four'}

6)setdefault(key[, default])

setdefault()方法和get()方法有點(diǎn)相似,但是,setdefault()在字典中找不到相應(yīng)的鍵時(shí)會(huì)自動(dòng)添加:

     >>> a = {1:"one", 2:"two", 3:"three", 4:"four"}
     >>> a.setdefault(3)
     'three'
     >>> a.setdefault(5)
     >>> a
     {1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: None}

7)update([other])

最后一個(gè)是update()方法,可以利用它來更新字典:

     >>> pets = {"米奇":"老鼠", "湯姆":"貓", "小白":"豬"}
     >>> pets.update(小白="狗")
     >>> pets
     {'米奇': '老鼠', '湯姆': '貓', '小白': '狗'}

還記得在6.2節(jié)的末尾我們埋下了一個(gè)伏筆,在講到收集參數(shù)的時(shí)候,我們說Python還有另一種收集方式,就是用兩個(gè)星號(hào)(**)表示。兩個(gè)星號(hào)的收集參數(shù)表示為將參數(shù)們打包成字典的形式,現(xiàn)在講到了字典,就順理成章地給大家講講吧。

收集參數(shù)其實(shí)有兩種打包形式:一種是以元組的形式打包;另一種則是以字典的形式打包。

當(dāng)參數(shù)帶兩個(gè)星號(hào)(**)時(shí),傳遞給函數(shù)的任意數(shù)量的key=value實(shí)參會(huì)被打包進(jìn)一個(gè)字典中。那么有打包就有解包,再來看下一個(gè)例子:

     >>> a = {"one":1, "two":2, "three":3}
     >>> test(**a)
     有 3 個(gè)參數(shù)
     它們分別是: {'three': 3, 'one': 1, 'two': 2}
主站蜘蛛池模板: 葵青区| 镇安县| 汕头市| 苍山县| 通渭县| 汾阳市| 乌拉特后旗| 庐江县| 江源县| 沈阳市| 永靖县| 永安市| 蓝山县| 乐平市| 建昌县| 静海县| 东城区| 洛隆县| 禹州市| 延庆县| 夹江县| 黄浦区| 景东| 榆林市| 铜陵市| 镇坪县| 新干县| 奉节县| 湟中县| 阜新市| 奉贤区| 思茅市| 榕江县| 甘肃省| 旬邑县| 郸城县| 洪江市| 广丰县| 奉新县| 鄂伦春自治旗| 长春市|