用 dict() 或大括弧建立名值對(key-value pair),和 list 與 tuple 一樣是用中括弧存取。
d = dict() # 與 d = {} 相同 dict1 = { 'name': 'Neil', 'sex': 'M', 'children': 2 } print(type(dict1)) # <class 'dict'> print(dict1) # {'name': 'Neil', 'sex': 'M', 'children': 2} print('I\'m ' + dict1['name']) #I'm Neil當然也可以使用 int 做 index,不過就是不必從 0 開始,也沒有排序。
特別注意 dict() 是內建的 Python 函式名稱,也就是說 dict 是「保留字」,不要拿來做變數名稱,不然會 debug 到瘋掉。
順序
dict 和 list 有一點很大的不同,就是 dict 沒有順序(也是因為 index 不是 int 的關係,很難排序),影響最大的就是 list 的 slice 完全不能用。但是這個特點有一個很特別的後果,即使在定義時 key 的順序不同,但只要結果是相同的(就是 key 和 value 完全相符),那就可以視為兩個相同的 dict,list 就不行這樣了。
print([ 'A', 'B', 'C' ] == [ 'A', 'B', 'C' ]) # True print([ 'A', 'B', 'C' ] == [ 'A', 'C', 'B' ]) # False print({ 'name': 'Neil', 'sex': 'M' } == { 'sex': 'M', 'name': 'Neil' }) # True可以使用 Python 內建函式 sorted() 對 dict 的 key 進行排序。
dict1 = { 'name': 'Neil', 'sex': 'M', 'children': 2 } print(dict1.keys()) # dict_keys(['name', 'sex', 'children']) print(sorted(dict1.keys())) # ['children', 'name', 'sex']存取不存在的 dict key 會得到 KeyError,存取不存在的 list index 會得到 IndexError。
dict.keys(), dict.values(), dict.items()
keys() 和 values() 都是回傳 list-like,而 items() 回傳的是 list-like of tuple。dict1 = { 'name': 'Neil', 'sex': 'M', 'children': 2 } print(dict1.keys()) # dict_keys(['name', 'sex', 'children']),順序是隨機的 print(dict1.values()) # dict_values(['Neil', 'M', 2]) print(dict1.items()) # dict_items([('name', 'Neil'), ('sex', 'M'), ('children', 2)]) print(len(dict1)) # 3,指 key 的數量list-like 不是真的 list,不能修改,但可以用在 for 迴圈裡,也可以用 list() 轉成真的 list。
dict1 = { 'name': 'Neil', 'sex': 'M', 'children': 2 } for k, v in dict1.items(): print(str(k) + ' > ' + str(v)) # name > Neil # sex > M # children > 2 for k in dict1: # 也可以這樣簡單用 print(str(k) + ' > ' + str(dict1[k]))也可以使用 in 與 not in 檢查 keys() 與 values() 是否存在。
print('sex' in dict1.keys()) # True print('sex' in dict1) # True,等同於 dict1.keys() print(2 in dict1.values()) # True
dict、tuple 與 zip
可以使用 list of tuple 或者 zip 建立或修改 dict。# 用 list of tuple 建立 dict d1 = dict([('Name', 'Neil'), ('Food', 'Banana'), ('Sport', 'Jogging')]) print(d1) # {'Name': 'Neil', 'Food': 'Banana', 'Sport': 'Jogging'} # 用 zip 建立 dict d2 = dict(zip(['Name', 'Food', 'Sport'], ['Neil', 'Banana', 'Jogging'])) print(d2) # {'Name': 'Neil', 'Food': 'Banana', 'Sport': 'Jogging'} # 用 list of tuple 更新 dict d1.update([('Food', 'Pineapple'), ('Learning', 'Python')]) print(d1) # {'Name': 'Neil', 'Food': 'Pineapple', 'Sport': 'Jogging', 'Learning': 'Python'} # 用 zip 更新 dict d2.update(zip(['Name', 'Like'], ['Emma', 'Sleep'])) print(d2) # {'Name': 'Emma', 'Food': 'Banana', 'Sport': 'Jogging', 'Like': 'Sleep'}
Hash 演算
不同於 list,dict 的 key 是用 Hash 演算,所以查詢非常快,在進行 in 查值時(x in list 或者 x in dict),list 的查詢時間是與 item 數量等比,但是 dict 的查詢時間不受 item 數量的影響。
一開始提到「幾乎」可以使用任意資料型別作為 dict 的 key,原因就在作為 key 的物件必須能進行 Hash 演算(Hashable),而 Hashable 的一個大前提就是 immutable,不然加入後又去變更值,就會改變 Hash 值,進而破壞 dict key 必須 unique 的規矩。
因此 list 與 dict 都不能做 dict 的 key,不過做 dict 的 value 是沒有限制的。
這裡發現第一個 tuple 存在的需求,tuple 可以視為唯讀的 list,也就是 immutable,當然可以作為 dict 的 key。
一開始提到「幾乎」可以使用任意資料型別作為 dict 的 key,原因就在作為 key 的物件必須能進行 Hash 演算(Hashable),而 Hashable 的一個大前提就是 immutable,不然加入後又去變更值,就會改變 Hash 值,進而破壞 dict key 必須 unique 的規矩。
因此 list 與 dict 都不能做 dict 的 key,不過做 dict 的 value 是沒有限制的。
dict.get(), dict.setdefault()
不想每次存取前都用 in 與 not int 檢查 key 是否存在,可以改用 get() 與 setdefault()。dict1 = { 'name': 'Neil', 'sex': 'M', 'children': 2 } print(dict1.get('name', 'CW')) # Neil,已存在,回傳原值 print(dict1) # {'name': 'Neil', 'sex': 'M', 'children': 2} print(dict1.get('married', True)) # True print(dict1) # {'name': 'Neil', 'sex': 'M', 'children': 2} print(dict1.setdefault('favorite', 'banana')) # banana print(dict1) # {'name': 'Neil', 'sex': 'M', 'children': 2, 'favorite': 'banana'} print(dict1.setdefault('favorite', 'chocolate')) # banana print(dict1) # {'name': 'Neil', 'sex': 'M', 'children': 2, 'favorite': 'banana'}get() 不存在的 key 不會修改 dict,setdefault() 不存在的 key 才會修改 dict。
使用 setdefault() 統計字串中字元出現的次數。
def charCount(s): count = {} for c in s: count.setdefault(c, 0) count[c] += 1 return countget() 的作法更簡潔。
def charCount(s): count = {} for c in s: count[c] = count.get(c, 0) + 1 return count
輸出
利用 pprint 可以輸出漂亮的 dict,尤其是巢狀堆疊時。dict1 = { 'name': 'Neil', 'sex': 'M', 'children': 2, 'nested': { 'name': 'Neil', 'sex': 'M', 'children': 2, 'nested': { 'name': 'Neil', 'sex': 'M', 'children': 2 }}} print(dict1) import pprint pprint.pprint(dict1)
有沒注意到,除了 list 與 str 加上續行符號可以忽略縮排,dict 也是,猜測 tuple 應該也可以吧。
---
---
---
沒有留言:
張貼留言