第五章:深入Python的set和dict

1. collections.abc模塊介紹

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 10:57'

from collections.abc import Mapping,MutableMapping
# dict是屬于Mapping類型的
a = {}
print(type(a)) # dict
print(isinstance(a,MutableMapping)) # 是屬于MutableMapping類型的
# 但是它不是通過繼承的方式,而是實現了這個類中的一些方法,通過MutableMapping.register(dict)的方法

2.字典的常見操作

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 11:04'
a = {'bob1': {'company': 'imooc'},
     'bob2': {'company': 'imooc2'}}
# clear 清空
# print(a)

# copy,淺拷貝,只拷貝了最外層的對象的引用,如果淺拷貝的
# 時候有可變對象的應用,則如果修改了原來的值,則可變對象的值也就跟著改變.
# 比如上面的a字典,key的拷貝不會出現問題.但是value的值本身也是一個引用類型,
# 它是可變的,拷貝的時候只是拷貝了這個內部字典的應用.所以如果它修改了,則原來的那個
# 對象也會跟著修改.
new_dict = a.copy()
new_dict['bob1']['company'] = 'imooc3'
print(a)
print(new_dict)
# {'bob1': {'company': 'imooc3'}, 'bob2': {'company': 'imooc2'}}
# {'bob1': {'company': 'imooc3'}, 'bob2': {'company': 'imooc2'}}

# fromkeys 將一個可迭代對象作為鍵,設定一個默認值,生成一個新字典
lst_keys = [1, 2, 3, 4]
new_dict = dict.fromkeys(lst_keys, 'a')
print(new_dict)

# get 根據鍵獲取值.類似dict[key] 的用法.
# 但是dict[key]用法有一個缺點,如果元素不在字典中會創建一個新的鍵

value = new_dict.get(1, '')  # 如果key為1的不存在或者沒有這個key,就會返回空
print(new_dict)
# value = new_dict[5] # 這里會報錯
new_dict[5] = 6  # 這里會重新創建一個鍵,只有這個鍵存在的時候才是修改對應的值
print(new_dict, new_dict[5])

# items()key,value的元組的列表
print(new_dict.items(), new_dict.keys(), new_dict.values())
# items()返回的是一個元組列表, keys()返回的是鍵的列表,values()返回的值列表

for key, value in new_dict.items():
    print(key, value)

# setdefault('7','d')  創建一個鍵,并且設置默認值
default_value = new_dict.setdefault(7, 'd')
print(new_dict)

# update() 可以將一個字典或者一個賦值表達式,或者一個元組列表合并到字典中
new_dict.update({8: 'a'})
new_dict.update(boby=3, boby2=4)
new_dict.update([(9, 'f'), (10, 'g')]) # 放一個元組列表
print(new_dict)

3.和字典相關的類

1. 當我們要自定義一個字典的時候,不要使用直接繼承自dict,因為有些操作會不生效

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 13:42'


class MyDict(dict):
    def __setitem__(self, key, value):
        super().__setitem__(key, value * 2)

my_dict = MyDict()
my_dict['a'] = 3  # 這個時候調用的是__setitem__方法
print(my_dict) # {'a': 6}

# 直接在構造函數中初始化字典,這個時候調用的應該是__call__方法
my_dict = MyDict(b=5)
print(my_dict) # {'b': 5}

# 所以最好不要繼承dict的方式,可以用繼承collections模塊的UserDict的方式

2. 使用繼承UserDict的方式來實現自定義的字典.

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 13:47'
from collections import UserDict


class MyDict(UserDict):
    def __setitem__(self, key, value):
        super().__setitem__(key, value * 2)

mydict = MyDict(a=4)
print(mydict)

mydict['b'] = 5
print(mydict)

3. 創建帶有默認值的字典. collections中的defaultdict
字典之所以可以實現帶有默認值,其實是它內部實現了__missing__方法,在UserDict類里面的__getitem__方法中會調用__missing__方法

    def __getitem__(self, key):
        if key in self.data:
            return self.data[key]
        if hasattr(self.__class__, "__missing__"):
            return self.__class__.__missing__(self, key)
        raise KeyError(key)

defaultdict之所以可以設置默認值就是因為實現了__missing__方法

4. set和frozenset

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 13:58'
# set 集合 frozenset(不可變集合),無序,不重復
s = set('abcdef')
print(s)
s1 = set(['a', 'b', 'c', 'd'])
print(s1)
# 通過大括號的方式直接賦值
s2 = {'a', 'b', 'c', 'd'}
print(s2)

# 1.集合可以添加元素
s2.add('f')
print(s2)

s = frozenset('abcde')  # frozenset 是不可變的集合,可以作為字典的key
# s.add() 錯誤,不可變集合不能添加數據

# 2.clear() 清空集合
# 3.copy() 淺拷貝集合
# 4.pop() 彈出最后一個元素
# 5.remove() 刪除一個集合元素
# 6.update()像set中添加一個集合
another_set = set('123')
s2.update(another_set)
print(s2)
# 7.difference(找不同)
ret_set = s2.difference(another_set)  # s - s2
print(ret_set)
# 8.求交集 &
ret_set = s2 & another_set
print(ret_set)
# 9.求并集
ret_set = s2 | another_set
print(ret_set)
# 10 in 對應的魔法方法__contains__
if 'a' in ret_set:
    pass
# 11. 判斷是否是子集
if s2.issubset(another_set)

5. dict和set的實現原理

dict和list的性能對比:
1. dict的性能遠遠大于list
2. list的查找時間,hi隨著list的數據的增多成正比例增加
3. 而dict的查找時間,不會隨著字典的增大而增大.

字典的內部是通過hash表來映射的,什么是hash表,通過字典的key算出一個hash值,這個hash值對應一個位置,這個位置存放著字典的key和value.而因為hash表的存放是連續的,類似于數組,它查找和存取是根據偏移量來進行的,所以不需要遍歷,就會速度很快.

注意:
set的值和字典的鍵的實現原理是一樣的,都是可以hash的.
不可變對象,都是可hash的.str,forzenset,tuple,自己實現的類實現了__hash__都是可hash的對象.都可以作為字典的鍵

dict的內存花銷大,但是查詢速度快,自定義對象,或者python的自定義對象,都是用字典的方式來存儲的.

dict的存儲順序和元素的添加順序有關
dict中添加元素的時候,有可能會改變原來的位置.當插入的數據過多,重新分配內存的時候,dict就有可能將原來的順序打亂.
所以一般使用dict的時候,不要期望它會一直維持某種順序.

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容