一、集合
??在 Python 中睦裳,集合由內(nèi)置的 set 類(lèi)型定義造锅。
??集合的特性:無(wú)序,元素唯一 廉邑,可變哥蔚。屬于散列類(lèi)型倒谷。
1. 創(chuàng)建和使用集合
??要?jiǎng)?chuàng)建集合,需要將所有項(xiàng)(元素)放在花括號(hào)({})內(nèi)糙箍,以逗號(hào)(,)分隔渤愁。
>>> se = {1,2,'a','b'} #{1, 2, 'b', 'a'}
>>> se3 = set() #用工廠方法定義空集合
>>> se4 = {} #<class 'dict'>
2. 特點(diǎn)
(1) 無(wú)序性
??集合里的元素具有無(wú)序性。
>>> se = {1,'s',55,5} # {'s', 1, 5, 55}
(2) 唯一性
??元素唯一深夯,會(huì)去掉重復(fù)元素
>>> se={1,1,1,1,3} # {1, 3}
>>> se3={1,2,[3,3,4]} ##TypeError: unhashable type: 'list' list不可哈希
#列表是可變的抖格,所以不能滿(mǎn)足唯一性
Hash()哈希函數(shù)可以檢驗(yàn)對(duì)象是不是可哈希的
>>> hash((1,2,3)) #元組可以哈希 3713081631934410656 返回的是哈希位置
>>> hash([1,2]) # TypeError: unhashable type: 'list'
(3) 可變
3. 集合的運(yùn)算
se={1, 2, 3炬称,4}
se2={3, 4, 5, 6}
(1) 屬于(元素與集合), 返回bool值
>>> 3 in se2 #True
>>> se in se2 #False
not in #不屬于
(2) 包含于(集合與集合), 返回bool值
>>> se < se2 #False
>>> se <= se2 #False
(3) 交集:&
??兩個(gè)集合共有的元素啦辐,即重復(fù)的部分,返回一個(gè)集合
>>> se & se2 #{3,4}
(4) 并集:|
??取兩個(gè)集合所有的元素荧飞,返回一個(gè)集合
>>> se | se2 #{1, 2, 3, 4, 5, 6}
(5) 差集:-
??前面的集合減去與后面的集合重復(fù)的元素掌呜,返回一個(gè)集合
>>> se - se2 #{1, 2}
(6) 與非集:^
??取兩個(gè)集合各自獨(dú)有的元素滓玖,返回一個(gè)集合
>>> se ^ se2 #{1, 2, 5, 6}
4. 集合的方法
>>> dir(set)
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']
(1) set.add(…)
??添加單個(gè)元素到集合里。隨機(jī)地添加到任意位置站辉。如果添加一個(gè)已存在的元素呢撞,這將沒(méi)有影響。無(wú)返回值饰剥。
>>> se.add(5) #{1,2,3,4,5}
(2) set.update(…)
??添加多個(gè)元素殊霞。要放入可迭代的對(duì)象。無(wú)返回值汰蓉。
>>> se.update('123') #{1,2,3,4,'1','2','3'}
>>> se.update([1,2,3]) #添加已存在的元素绷蹲,會(huì)自動(dòng)去重
>>> se.update(1,2,3) # TypeError: 'int' object is not iterable
(3)set.remove(…)
??指定移除一個(gè)集合里存在的元素,如果元素不在集合里顾孽,會(huì)拋出KeyError祝钢。無(wú)返回值。
>>> se.remove(1) #{2, 3, 4, '3', '2', '1'}
>>> se.remove('1') #{2, 3, 4, '3', '2'}
>>> se.remove(7) #KeyError: 7
(4)set.clear()
??移除集合里所有的元素若厚。無(wú)返回值拦英。
>>> se.clear() #{}
二、字典
??這里介紹一種可通過(guò)名稱(chēng)來(lái)訪問(wèn)其各個(gè)值的數(shù)據(jù)結(jié)構(gòu)测秸。這種數(shù)據(jù)結(jié)構(gòu)稱(chēng)為映射(mapping)疤估。字典是Python中唯一的內(nèi)置映射類(lèi)型,其中的值不按順序排列霎冯,而是存儲(chǔ)在鍵下铃拇。鍵可能是數(shù)、字符串或元組沈撞。
??字典是另一種可變?nèi)萜髂P涂独螅纱鎯?chǔ)任意類(lèi)型的對(duì)象。
??字典的特性 : key 唯一缠俺, 無(wú)序 显晶, 可變贷岸。屬于散列類(lèi)型。
1. 字典的用途
??字典(日常生活中的字典和Python字典)旨在讓你能夠夠輕松地找到特定的單詞(鍵)吧碾,以獲悉其定義(值)凰盔。
在很多情況下,使用字典都比使用列表更合適倦春。下面是Python字典的一些用途:
- 表示棋盤(pán)的狀態(tài)户敬,其中每個(gè)鍵都是由坐標(biāo)組成的元組
- 存儲(chǔ)文件修改時(shí)間,其中的鍵為文件名
- 數(shù)字電話/地址簿
??假如有如下的名單:
>>> names = ['Alice', 'Beth', 'Cecil', 'Dee-Dee', 'Earl']
??如果創(chuàng)建一個(gè)小型數(shù)據(jù)庫(kù)睁本,在其中存儲(chǔ)這些人的電話號(hào)碼尿庐,該如何辦呢?一種方法是再創(chuàng)建一個(gè)列表呢堰。假設(shè)只存儲(chǔ)四位的分機(jī)號(hào)抄瑟,這個(gè)列表將類(lèi)似于:
>>> numbers = ['2341', '9102', '3158', '0142', '5551']
??創(chuàng)建這些列表后,就可像下面這樣查找Cecil的電話好嗎:
>>> numbers[names.index('Cecil')] #'3158'
??這可行枉疼,但不太實(shí)用皮假。實(shí)際上,你希望能干過(guò)像下面這樣做:
>>> phonebool['Cecil'] #'3158'
??如何達(dá)成這個(gè)目標(biāo)呢骂维?只要phonebook是個(gè)字典就行了惹资。
2. 創(chuàng)建和使用字典
??字典以類(lèi)似于下面的方式表示:
Phonebook = {'Alice':'2341', 'Beth'':'9102','Cecil':'3258'}
??字典由鍵及其相應(yīng)的值組成,這種鍵-值對(duì)稱(chēng)為項(xiàng)(item)航闺。在前面的示例中褪测,鍵為名字,而值為電話號(hào)碼潦刃。每個(gè)鍵與其值之間都用冒號(hào)(:)分隔侮措,項(xiàng)之間用逗號(hào)(,)分隔,而整個(gè)字典放在花括號(hào)內(nèi)乖杠》衷空字典(沒(méi)有任何項(xiàng))用兩個(gè)花括號(hào)表示,類(lèi)似于下面這樣:{}胧洒。
??注意:在字典(以及其他映射類(lèi)型)中笆包,鍵必須是獨(dú)一無(wú)二的,如果同一個(gè)鍵被賦值兩次略荡,后面的值會(huì)被記住,而字典中的值無(wú)需如此歉胶。值可以取任何數(shù)據(jù)類(lèi)型汛兜,鍵必須是不可變的,如字符串通今、數(shù)字或元組粥谬。
>>> di={'a':111,'b':222,'c':333}
>>> di={} #class 'dict'
3. 函數(shù)dict
??可使用函數(shù)dict從其他映射(如其他字典)或鍵-值對(duì)序列創(chuàng)建字典肛根。
>>> items = [('name', 'Gumby'), ('age', 42)]
>>> d = dict(items)
>>> d #{'age': 42, 'name': 'Gumby'}
>>> d['name'] #'Gumby' 取值
??還可使用關(guān)鍵字實(shí)參來(lái)調(diào)用這個(gè)函數(shù),如下所示:
>>> d = dict(name='Gumby', age=42)
>>> d #{'age': 42, 'name': 'Gumby'}
>>> di2=dict(a=111) #{'a': 111}
#di2 = (2_a=111) #報(bào)錯(cuò)
#di2 = (_a=111) #報(bào)錯(cuò)
??鍵要符合變量的命名規(guī)則
>>> di['c']=3 #{'c': 3} 修改
4. 基本的字典操作
字典的基本行為在很多方面都類(lèi)似于序列漏策。
- len(d)返回字典d包含的項(xiàng)(鍵值對(duì))數(shù)派哲。
- d[k]返回與鍵k相關(guān)聯(lián)的值。
- d[k] = v將值v關(guān)聯(lián)到鍵k掺喻。
- del d[k]刪除鍵為k的項(xiàng)芭届。del d刪除整個(gè)字典。
- k in d檢查字典d是否包含鍵為k的項(xiàng)感耙。
??雖然字典和列表有多個(gè)相同之處褂乍,但也有一些重要的不同之處。
- 鍵的類(lèi)型:字典中的鍵可以是整數(shù)即硼,但并非必須是整數(shù)逃片。字典中的鍵可以是任何不可變的類(lèi)型,如浮點(diǎn)數(shù)(實(shí)數(shù))只酥、字符串或元組褥实。
- 自動(dòng)添加:即便是字典中原本沒(méi)有的鍵,也可以給它賦值裂允,這將在字典中創(chuàng)建一個(gè)新項(xiàng)损离。然而,如果不使用append或其他類(lèi)似的方法叫胖,就不能給列表中沒(méi)有的元素賦值草冈。
- 成員資格:表達(dá)式k in d(其中d是一個(gè)字典)查找的是鍵而不是值,而表達(dá)式v in l(其中l(wèi)是一個(gè)列表)查找的是值而不是索引瓮增。這看似不太一致怎棱,但你習(xí)慣后就會(huì)覺(jué)得相當(dāng)自然。畢竟如果字典包含指定的鍵绷跑,檢查相應(yīng)的值就很容易拳恋。
??提示:相比于檢查列表是否包含指定的值,檢查字典是否包含指定的鍵的效率更高砸捏。數(shù)據(jù)結(jié)構(gòu)越大谬运,效率差距就越大。
5. 將字符串格式設(shè)置功能用于字典
??在第3章介紹過(guò)垦藏,可使用字符串格式設(shè)置功能來(lái)設(shè)置值的格式梆暖,這些值是作為命名或非命名參數(shù)提供給方法format的。在有些情況下掂骏,通過(guò)在字典中存儲(chǔ)一些列命名的值轰驳,可讓格式設(shè)置更容易些。
??例如,可在字典中包含各種信息级解,這樣只需在格式字符串中提取所需的信息即可冒黑。為此,必須使用format_map來(lái)指出你講通過(guò)一個(gè)映射來(lái)提供所需的信息勤哗。
>>> phonebook #{'Beth': '9102', 'Alice': '2341', 'Cecil': '3258'}
>>> "Cecil's phone number is {Cecil}.".format_map(phonebook)
#"Cecil's phone number is 3258.
??像這樣使用字典時(shí)抡爹,可指定任意數(shù)量的轉(zhuǎn)換說(shuō)明符,條件是所有的字段名都是包含在字典中的鍵芒划。
6.字典方法
>>> dir(dict)
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
(1) dict.clear()
d.clear() -> None.
??刪除所有的字典項(xiàng)冬竟,無(wú)返回值。
??這為何很有用呢腊状?我們來(lái)看兩個(gè)場(chǎng)景诱咏。下面是第一個(gè)場(chǎng)景:
>>> x = {}
>>> y = x
>>> x['key'] = 'value'
>>> y #{'key': 'value'}
>>> x = {}
>>> y #{'key': 'value'}
下面是第二個(gè)場(chǎng)景:
>>> x = {}
>>> y = x
>>> x['key'] = 'value'
>>> y #{'key': 'value'}
>>> x.clear()
>>> y #{}
??在這兩個(gè)場(chǎng)景中, x和y最初都指向同一個(gè)字典缴挖。在第一個(gè)場(chǎng)景中袋狞,我通過(guò)將一個(gè)空字典賦給x來(lái)“清空”它。這對(duì)y沒(méi)有任何影響映屋,它依然指向原來(lái)的字典苟鸯。這種行為可能正是你想要的,但要?jiǎng)h除原來(lái)字典的所有元素棚点,必須使用clear早处。如果這樣做, y也將是空的瘫析,如第二個(gè)場(chǎng)景所示砌梆。
(2) dict.copy(…)
??d.copy() -> a shallow copy of D
??方法copy返回一個(gè)新字典,其包含的鍵-值對(duì)與原來(lái)的字典相同(這個(gè)方法執(zhí)行的是淺復(fù)制贬循,因?yàn)橹当旧硎窃贪歉北荆?/p>
>>> 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['machines'][0]='aaa' #原值一起變化
>>> x #{'username': 'henry', 'machines': ['aaa', 'baz']}
>>> y #{'username': 'mlh', 'machines': ['aaa', 'baz']}
??如你所見(jiàn),當(dāng)替換副本中的值時(shí)杖虾,原件不受影響烂瘫。然而,如果修改副本中的值(就地修改而不是替換)奇适,原件也將發(fā)生變化坟比,因?yàn)樵赶虻囊彩潜恍薷牡闹怠?br> ??為避免上述問(wèn)題可以使用copy模塊中的deepcopy函數(shù)來(lái)執(zhí)行深復(fù)制,即同時(shí)復(fù)制值及其包含的所有值嚷往。
>>> from copy import deepcopy
>>> d = {}
>>> d['names'] = ['Alfred', 'Bertrand']
>>> c = d.copy()
>>> dc = deepcopy(d)
>>> d['names'].append('Clive')
>>> c #{'names': ['Alfred', 'Bertrand', 'Clive']}
>>> dc #{'names': ['Alfred', 'Bertrand']}
(3) dict.fromkeys(…)
??fromkeys(iterable, value=None, /) method of builtins.type instance
??Returns a new dict with keys from iterable and values equal to value.
??方法fromkeys創(chuàng)建一個(gè)新字典葛账,其中包含指定的鍵,且每個(gè)鍵對(duì)應(yīng)的值都是None皮仁。返回一個(gè)新字典注竿。
>>> {}.fromkeys(['name', 'age']) #{'age': None, 'name': None}
??這個(gè)示例首先創(chuàng)建了一個(gè)空字典茄茁,再對(duì)其調(diào)用方法fromkeys來(lái)創(chuàng)建另一個(gè)字典,這顯得有點(diǎn)多余巩割。你可以不這樣做,而是直接對(duì)dict(前面說(shuō)過(guò)付燥, dict是所有字典所屬的類(lèi)型)調(diào)用方法fromkeys宣谈。
>>> dict.fromkeys(['name', 'age']) #{'age': None, 'name': None}
??如果你不想使用默認(rèn)值None,可提供特定的值键科。這里只能批量生成闻丑,所以只能放一個(gè)值。
>>> dict.fromkeys(['name', 'age'], '(unknown)')
#{'age': '(unknown)', 'name': '(unknown)'}
(4) dict.get(…)
??d.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
??方法get查詢(xún)鍵在不在字典里面勋颖,如果鍵k在嗦嗡,返回鍵k的值,不存在則返回None或者可以自定義返回值饭玲。
>>> di = {'a':111, 'b':222, 'c':3, 'd':444}
>>> di.get('c') #3
>>> di.get('e')
??你可指定“默認(rèn)值”侥祭,這樣將返回你指定的值而不是None。
>>> di.get('e','wobuzai') #'wibuzai'
>>> di.get('c','wobuzai') #3
??通常茄厘,如果你試圖訪問(wèn)字典中沒(méi)有的項(xiàng)矮冬,將引發(fā)錯(cuò)誤。而使用get在訪問(wèn)字典中不存在的項(xiàng)時(shí)默認(rèn)返回None次哈,并且不會(huì)引發(fā)上述錯(cuò)誤胎署。
>>> d = {}
>>> print(d['name'])
Traceback (most recent call last):
File "<stdin>", line 1, in ?
KeyError: 'name'
??而使用get不會(huì)這樣:
>>> print(d.get('name')) #None
??如果字典包含指定的鍵, get的作用將與普通字典查找相同窑滞。
>>> d['name'] = 'Eric'
>>> d.get('name') #'Eric'
(5) dict.items()
??d.items() -> a set-like object providing a view on D's items
??方法items返回一個(gè)包含所有字典項(xiàng)的列表迭代器琼牧,其中每個(gè)元素都為(key, value)的元組形式。字典項(xiàng)在列表中的排列順序不確定哀卫。
>>> di.items()
#dict_items([('a', 111), ('b', 222), ('c', 3), ('d', 444)])
??然而巨坊,如果你要將字典項(xiàng)復(fù)制到列表中,可自己動(dòng)手做聊训。
>>> list(di.items())
#[('a', 111), ('b', 222), ('c', 3), ('d', 444)]
??返回值屬于一種名為字典視圖的特殊類(lèi)型抱究,字典視圖可用于迭代。另外带斑,你還可確定其長(zhǎng)度以及對(duì)其執(zhí)行成員資格檢查鼓寺。
>>> it = di.items()
>>> len(it) #4
>>> ('a', 111) in it #True
??視圖的一個(gè)優(yōu)點(diǎn)是不復(fù)制,它們始終是底層字典的反映勋磕。當(dāng)?shù)讓幼值涞膬?nèi)容被修改時(shí)妈候,視圖呈現(xiàn)出來(lái)的是修改后的值。
>>> di['a'] = 99
>>> ('a', 111) in it #False
>>> di['a'] = 0
>>> ('a', 0) in it #True
(6) dict.keys()
??d.keys() -> a set-like object providing a view on D's keys
??方法keys返回一個(gè)字典視圖挂滓,其中包含指定字典中的鍵苦银。
>>> di.keys()
#dict_keys(['a', 'b', 'c', 'd'])
(7) dict.values()
??d.values() -> an object providing a view on D's values
??方法values返回一個(gè)字典視圖,其中包含指定字典中的值。不同于方法keys幔虏,方法values返回的視圖可能包含重復(fù)的值纺念。
>>> di.values()
#dict_values([99, 222, 3, 444])
(8) dict.pop()
??d.pop(k[,d]) -> v
??方法pop可用于獲取與指定鍵相關(guān)聯(lián)的值,并將該鍵-值對(duì)從字典中刪除想括。
>>> di.pop('c') #3
>>> di # {'a': 99, 'b': 222, 'd': 444}
>>> di.pop() #會(huì)不會(huì)像list,pop()一樣刪除最后一個(gè)項(xiàng)呢陷谱?
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
di.pop()
TypeError: pop expected at least 1 arguments, got 0
(9) dict.popitem()
??d.popitem() -> (k, v)
??方法popitem類(lèi)似于list.pop,但list.pop彈出列表中的最后一個(gè)元素瑟蜈,而popitem隨機(jī)地彈出一個(gè)字典項(xiàng)烟逊,因?yàn)樽值漤?xiàng)的順序是不確定的,沒(méi)有“最后一個(gè)元素”的概念铺根。如果你要以高效地方式逐個(gè)刪除并處理所有字典項(xiàng)宪躯,這可能很有用,因?yàn)檫@樣無(wú)需先獲取鍵列表位迂。返回字典中被刪除的一項(xiàng)访雪。
>>> di.popitem() #('d', 444)
??如果字典為空字典,則會(huì)拋出KeyError
>>> di2={}
>>> di2.popitem()
Traceback (most recent call last):
File "<pyshell#18>", line 1, in <module>
di2.popitem()
KeyError: 'popitem(): dictionary is empty'
(10) dict.setdefault(…)
??d.setdefault(k[,d]) -> d.get(k,d), also set D[k]=d if k not in D
??方法setdefault有點(diǎn)像get囤官,因?yàn)樗搏@取與指定鍵相關(guān)聯(lián)的值冬阳,但除此之外,setdefault還在字典不包含指定的鍵時(shí)党饮,在字典中添加指定的鍵-值對(duì)肝陪。
>>> di = {'a': 99, 'b': 222}
>>> di.setdefault('a') #99
>>> di.setdefault('e')
>>> di #{'a': 99, 'b': 222, 'e': None}
>>> di.setdefault('e')
>>> di.setdefault('d',444) #{'a': 111, 'b': 222, 'c': None, 'd': 444}
??類(lèi)似get,但是能改變字典刑顺。
>>> di.setdefault('a',666) #111
??如你所見(jiàn)氯窍,指定的鍵不存在時(shí),setdefault返回指定的值并相應(yīng)地更新字典蹲堂。如果指定的鍵存在狼讨,就返回其值,并保持字典不變柒竞。與get一樣政供,值是可選的;如果沒(méi)有指定朽基,默認(rèn)為None布隔。
(11) dict.update()
??d.update([E, ]**F)
-> None. Update d from dict/iterable E and F.
If E is present and has a .keys() method, then does: for k in E: d[k] = E[k]
If E is present and lacks a .keys() method, then does: for k, v in E: d[k] = v
In either case, this is followed by: for k in F: d[k] = F[k]
??方法update使用一個(gè)字典中的項(xiàng)來(lái)更新另一個(gè)字典。
>>> di = {'a': 99, 'b': 222, 'e': None}
>>> x = {'a':123,'f':555}
>>> di.update(x)
>>> di #{'a': 123, 'b': 222, 'e': None, 'f': 555}
??對(duì)于通過(guò)參數(shù)提供的字典稼虎,將其項(xiàng)添加到當(dāng)前字典中衅檀。如果當(dāng)前字典包含鍵相同的項(xiàng),就替換它霎俩。
??可像調(diào)用本章前面討論的函數(shù)dict(類(lèi)型構(gòu)造函數(shù))那樣調(diào)用方法update哀军。這意味著調(diào)用update時(shí)沉眶,可向它提供一個(gè)映射、一個(gè)由鍵?值對(duì)組成的序列(或其他可迭代對(duì)象)或關(guān)鍵字參數(shù)杉适。
7. 字典和列表的區(qū)別
dict的特點(diǎn):
- 查找和插入的速度極快谎倔,不會(huì)隨著key的增加而變慢。
- 需要占用大量?jī)?nèi)存淘衙,內(nèi)存浪費(fèi)多传藏。
List的特點(diǎn)是:
- 查找和插入時(shí)間隨著元素的增加而增加。
- 占用空間小彤守,浪費(fèi)內(nèi)存很少。
所以哭靖,dict是使用空間換取時(shí)間具垫。
8. 可變,不可變
??可變试幽,不可變:就在id不變的情況下筝蚕,增值,改值
id() # 每個(gè)對(duì)象有唯一的 id
??如何區(qū)分一個(gè)對(duì)象铺坞,是否 可變
hash() # 成一個(gè) 唯一的哈希值起宽。
??如果不能被hash,就說(shuō)明這對(duì)象是可變的