第三章--字典與集合

第三章–字典與集合

本章內容的大綱如下:
• 常見的字典方法
• 如何處理查找不到的鍵
• 標準庫中 dict 類型的變種
• set 和 frozenset 類型
• 散列表的工作原理
• 散列表帶來的潛在影響(什麼樣的數據類型可作爲鍵、不可預知的順序,等等)

3.1泛映射類型

collections.abc模塊中有Mapping和MutableMapping兩個抽象基類,作用是給dict或其他類似的映射類型定義接口,還有可以用與isinstance()判斷某個數據是否是映射類型
在這裏插入圖片描述

標準庫中所有映射類型都是利用dict實現了,限制是只有hashable的數據類型纔可以作爲映射的key

關於hashbale的一些解釋

  • 原子不可變數據類型 str、bytes、數值類型都是hashable的
  • frozenset是hashable的,因爲根據其定義frozenset裏只能容納hashable類型
  • 元祖只有它包含的所有元素都是hashable的,它纔是hashable的
tt=(1,2,(30,40))
print(hash(tt)) # sucess
tl=(1,2,[30,40])
print(hash(tl)) # TypeError: unhashable type: '
Called by built-in function hash() and for operations on members of hashed collections including set, frozenset, and dict. 
  1. 關鍵是__hash__跟__eq__的實現
  2. hash跟eq都不實現的話會用object的hash跟eq函數,object的hash跟eq都是返回對象的內存地址,這時a1==a2 a1 is a2 hash(a1)==hash(a2)的返回值都是一樣的,如果a1 a2都是指向同一個對象的話,結果都是True ,如果a1 a2不是指向同一對象,結果都爲False
class ClassA():

    def __init__(self):
        self.name='jason'


a1=ClassA()
a2=ClassA()
print(a1==a2, a1 is a2, hash(a1)==hash(a2)) # False False False
a2=a1
print(a1==a1, a1 is a2, hash(a1)==hash(a2)) # True True True
  1. 自定義hash,不實現eq,這樣會用到object的eq函數,作爲dict的key值時會調用hash跟eq函數,如果兩個key的hash相同,還會調用key的eq函數,如果eq結果爲False,那麼會把兩個key識別爲不同,儘管他們的hash相同,如下面的代碼,dic最終有兩個key
class ClassA():

    def __init__(self):
        self.name='jason'

    def __hash__(self):
        print('ClassA Hash method')
        return hash(self.name)


a1=ClassA()
a2=ClassA()
print(a2.__hash__)
dic={}
dic[a1]=1
dic[a2]=2
print(dic)

# <bound method ClassA.__hash__ of <__main__.ClassA object at 0x000001283708D160>>
# ClassA Hash method
# ClassA Hash method
# {<__main__.ClassA object at 0x000001283708D438>: 1, <__main__.ClassA object at 0x000001283708D160>: 2}
  1. 自定義eq不定義hash,只定義了eq的話hash方法會變爲None,不可調用,此時不能作爲dict的key
class ClassA():

    def __init__(self):
        self.name='jason'

    def __eq__(self, other):
        print('ClassA Eq method')
        return self.name==other.name


a1=ClassA()
a2=ClassA()
print(a2.__hash__) # None
dic={}
dic[a1]=1  # TypeError: unhashable type: 'ClassA'
dic[a2]=2
print(dic)
  1. 如果同時定義了hash跟eq,作爲dict的key時都會調用,只有兩個變量hash值相同,eq返回True時才能判定爲同一個key,下面兩處代碼分別展示了兩個變量hash值相同,但eq返回True跟False的情況
class ClassA():

    def __init__(self):
        self.name='jason'

    def __hash__(self):
        print('ClassA Hash method')
        return hash(self.name)
    def __eq__(self, other):
        print('ClassA Eq method')
        return self.name==other.name


a1=ClassA()
a2=ClassA()
print(a2.__hash__)
dic={}
dic[a1]=1
dic[a2]=2
print(dic)

# <bound method ClassA.__hash__ of <__main__.ClassA object at 0x000001EEFFE1D470>>
# ClassA Hash method
# ClassA Hash method
# ClassA Eq method
# {<__main__.ClassA object at 0x000001EEFFE1D160>: 2}
class ClassA():

    def __init__(self):
        self.name='jason'

    def __hash__(self):
        print('ClassA Hash method')
        return hash(self.name)
    def __eq__(self, other):
        print('ClassA Eq method')
        # return self.name==other.name
        return self.name=='mike'


a1=ClassA()
a2=ClassA()
print(a2.__hash__)
dic={}
dic[a1]=1
dic[a2]=2
print(dic)

# <bound method ClassA.__hash__ of <__main__.ClassA object at 0x00000201586FD4E0>>
# ClassA Hash method
# ClassA Hash method
# ClassA Eq method
# {<__main__.ClassA object at 0x00000201586FD470>: 1, <__main__.ClassA object at 0x00000201586FD4E0>: 2}
  1. 參考:
    https://blog.csdn.net/sinat_38068807/article/details/86519944
    https://blog.csdn.net/lnotime/article/details/81194962

3.2字典推導

跟列表推導式類似
實現key跟value的互換:dic={value,key for key,value in other_dic.items()}

3.3 常見的映射方法

展示了dict、collections.defaultdict、collections.OrdereDict的方法列表
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

3.4 映射的彈性key查詢

有時候爲了方便起見,就算某個鍵在映射裏不存在,我們也希望在通過這個鍵讀取值的
時候能得到一個默認值。有兩個途徑能幫我們達到這個目的,一個是通過 defaultdict 這
個類型而不是普通的 dict,另一個是給自己定義一個 dict 的子類,然後在子類中實現
__missing__ 方法。

  • defaultdict
    舉例 dd=collections.defaultdict(list)
    執行dd[key]時,如果key在dd.keys()裏則返回dd[key],如果key不在的話就會調用list()得到默認值賦值給dd[key],並返回列表的引用
    在這裏插入圖片描述
  • __missing__方法
    __missing__方法只會被__getitem__調用,跟get或者__contains__無關,這個跟defaultdict的default_factory一個道理,當d[key]找不到key對應的值後就會調用missing方法

3.5 字典的變種

  • collections.OrderedDict
    添加key時會保持順序,key的迭代順序是一致的,popitem默認刪除字典最後一個元素,如果是popitem(last=False)的話會刪除第一個元素
  • collections.ChainMap
    通過鏈式的形式存儲多個映射對象,在查找key時對所有映射對象進行查詢
    查詢會查詢所有對象,修改只會修改第一個映射對象裏的key
from collections import ChainMap

dicA={'a':1,'b':2}
dicB={'b':3,'c':4}
cm=ChainMap(dicA,dicB)
print(cm)# ChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4})
print(cm['b']) # 2
cm.pop('b')
print(cm) # ChainMap({'a': 1}, {'b': 3, 'c': 4})
print(dicA) # {'a': 1}
print(cm['b']) # 3
cm.pop('c') # KeyError: "Key not found in the first mapping: 'c'"

  • collections.Counter
    給key準備一個整數計數器,每次更新一個key時增加家屬器
from collections import Counter

ct=Counter('abcdefg')
print(ct)
ct.update('aaaabbddd')
print(ct)
print(ct.most_common(2))

# Counter({'a': 1, 'b': 1, 'c': 1, 'd': 1, 'e': 1, 'f': 1, 'g': 1})
# Counter({'a': 5, 'd': 4, 'b': 3, 'c': 1, 'e': 1, 'f': 1, 'g': 1})
# [('a', 5), ('d', 4)]
  • collections.UserDict
    把標準dict用純Python又實現了一遍,3.6詳細介紹

3.6子類化UserDict

UserDict並不是dict的子類,更像是對dict的一個封裝,UserDict有一個data屬性,是dict實例,實際上data是數據最終存儲的地方,我們構建映射類繼承UserDict而不是dict,可以避免dict隱式調用自身的某些方法

3.7不可變映射類型

不可變映射類型意思是指用戶能讀取映射的值,但不能添加新key或修改value值

from types import MappingProxyType

d={'a':1}
mp=MappingProxyType(d)
print(mp)# {'a': 1}
print(mp['a']) # 1
# mp['b']=2 # TypeError: 'mappingproxy' object does not support item assignment
# mp['a']=3 # TypeError: 'mappingproxy' object does not support item assignment
d['a']=4
print(mp) # {'a': 4}

3.8集合論

集合中的元素必須是hashable的,set類型本身不是hashable的,但是frozenset可以,因此可以創建一個包含不同frozenset的set
集合的運算 集合a、b a|b返回合集 a&b返回交集,a-b返回差集
集合推導,跟字典推導類似
s={key for key in my_dict.keys()}

在這裏插入圖片描述
集合的函數列舉
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

dict和set的背後原理

dict和set背後都是用散列表
給予散列表實現的dict和set有以下特點

  • 集合裏的元素必須是可散列的。
  • 集合很消耗內存。
  • 可以很高效地判斷元素是否存在於某個集合。
  • 元素的次序取決於被添加到集合裏的次序。
  • 往集合裏添加元素,可能會改變集合裏已有元素的次序。
    注意,不要在遍歷dict和set的同時對他們的值進行修改,這可能導致某些值不被遍歷到
    dict的keys items values方法返回的都是字典視圖,而不是列表
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章