Python 中的dict類別提供了許多實用的方法來處理字典。
有些方法已在dicts概念中介紹過。
這裡我們會再介紹一些方法,以及一些疊代與操作字典的技巧。
setdefault()進行無錯誤插入字典概念先前介紹過,.get(key, <default value>)會回傳既有的value,或在字典中找不到key時回傳default value,藉此避免KeyError。
當你不想加入額外的錯誤處理,卻又無法確定要找的key是否存在時,這種做法就很好用。
如果需要類似這種「安全」(不會觸發 KeyError)的插入操作,可以使用.setdefault(key, <default value>)方法。
如果字典中找到key,setdefault(key, <default value>)會回傳對應的value。
如果沒有找到該鍵,它會_插入_(key, default value)鍵值對,並回傳default value供後續使用。
>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
# Looking for the value associated with key "Rock Brown".
# The key does not exist, so it is added with the default value, and the value is returned.
>>> palette_I.setdefault('Rock Brown', '#694605')
'#694605'
# The (key, default value) pair has now been added to the dictionary.
>>> palette_I
{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Rock Brown': '#694605'}
fromkeys()從可疊代物件填入字典若要快速用各種keys與預設值填入字典,可以使用_類別方法_fromkeys(iterable, <default value>),它會疊代一組keys並建立新的dict。
所有的values都會被設為所提供的default value:
>>> new_dict = dict.fromkeys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'], 'fill in hex color here')
{'Grassy Green': 'fill in hex color here',
'Purple Mountains Majesty': 'fill in hex color here',
'Misty Mountain Pink': 'fill in hex color here'}
.keys()、.values()和.items()方法會回傳字典的可疊代檢視。
這些檢視可以讓你輕鬆地對項目進行迴圈,而不會更動它們。
檢視也是_動態_的,當底層字典資料改變時,相關的view object也會跟著反映這些變更:
>>> palette_I = {'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd'}
# Using .keys() returns a list of keys.
>>> palette_I.keys()
dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'])
# Using .values() returns a list of values.
>>> palette_I.values()
dict_values(['#9bc400', '#8076a3', '#f9c5bd'])
# Using .items() returns a list of (key, value) tuples.
>>> palette_I.items()
dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', '#8076a3'), ('Misty Mountain Pink', '#f9c5bd')])
# Views are dynamic. Changing values in the dict changes all of the associated views.
>>> palette_I['Purple Mountains Majesty'] = (128, 118, 163)
>>> palette_I['Deep Red'] = '#932432'
>>> palette_I.values()
dict_values(['#9bc400', (128, 118, 163), '#f9c5bd', '#932432'])
>>> palette_I.keys()
dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink', 'Deep Red'])
>>> palette_I.items()
dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', (128, 118, 163)), ('Misty Mountain Pink', '#f9c5bd'), ('Deep Red', '#932432')])
.keys()、.values()和.items()的更多說明在 Python 3.7+ 中,dicts會保留項目插入的順序,讓你在使用.keys()、.values()或.items()時能以先進先出(FIFO)的方式疊代。
在 Python 3.8+ 中,檢視也變得_可反轉_。
如此一來,只要使用reversed(<dict>.keys())、reversed(<dict>.values())或reversed(<dict>.items()),就能以後進先出(LIFO)的順序疊代鍵、值或(key, value)鍵值對:
>>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
# Iterating in insertion order (First in, first out)
>>> for item in palette_II.items():
... print(item)
...
('Factory Stone Purple', '#7c677f')
('Green Treeline', '#478559')
('Purple baseline', '#161748')
# Iterating in the reverse direction. (Last in, first out)
>>> for item in reversed(palette_II.items()):
... print (item)
...
('Purple baseline', '#161748')
('Green Treeline', '#478559')
('Factory Stone Purple', '#7c677f')
字典沒有內建的排序方法。
不過,可以使用內建函式sorted()搭配dict.items()來排序dict的_檢視_。
排序後的檢視接著可以用來建立新的字典。
和疊代一樣,預設的排序方式是依據字典的keys。
# Default ordering for a dictionary is insertion order (First in, first out).
>>> color_palette = {'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd',
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple baseline': '#161748'}
# The default sort order for a dictionary uses the keys.
>>> sorted_palette = dict(sorted(color_palette.items()))
>>> sorted_palette
{'Factory Stone Purple': '#7c677f',
'Grassy Green': '#9bc400',
'Green Treeline': '#478559',
'Misty Mountain Pink': '#f9c5bd',
'Purple Mountains Majesty': '#8076a3',
'Purple baseline': '#161748'}
.update()合併字典<dict_one>.update(<dict_two>)可以用來_合併_兩個字典。
這個方法會取出<dict_two>的(key,value)鍵值對,並把它們寫入<dict_one>:
>>> palette_I = {'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd'}
>>> palette_II = {'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple Baseline': '#161748'}
>>> palette_I.update(palette_II)
# Note that new items from palette_II are added.
>>> palette_I
{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple Baseline': '#161748'}
當兩個字典的鍵_重疊_時,dict_one中的value會被dict_two對應的value覆寫:
>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd',
'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
>>> palette_III = {'Grassy Green': (155, 196, 0), 'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189)}
>>> palette_I.update(palette_III)
# Overlapping values in palette_I are replaced with values from palette_III
>>> palette_I
{'Grassy Green': (155, 196, 0),
'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189),
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559', 'Purple baseline': '#161748'}
|與|=)合併或更新字典Python 3.9 導入了另一種合併dicts的方式:union運算子。
dict_one | dict_two會建立一個新字典,內容由dict_one與dict_two的(key, value)鍵值對組成。
當兩個字典有相同的鍵時,以dict_two的值為優先。
>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
>>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
>>> new_dict = palette_I | palette_II
>>> new_dict
...
{'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd',
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple baseline': '#161748'}
dict_one |= other的行為類似<dict_one>.update(<other>),不過這裡的other可以是dict,也可以是(key, value)鍵值對的可疊代物件:
>>> palette_III = {'Grassy Green': (155, 196, 0),
'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189)}
>>> new_dict |= palette_III
>>> new_dict
...
{'Grassy Green': (155, 196, 0),
'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189),
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple baseline': '#161748'}
如果想深入了解字典以及操作字典的各種方法,官方教學和官方函式庫參考文件是非常好的起點。
Real Python和Finxter也有非常詳盡的 Python 字典文章。
Mecha Munch™ 是一家生鮮雜貨購物自動化公司,他們剛雇用你來開發他們的訂購應用程式。 你的團隊負責打造一個 MVP(最小可行產品),用來管理所有基本的購物車操作,讓使用者可以新增、移除及排序他們的雜貨訂單。 幸運的是,金流和結帳功能由另一個團隊負責!
MVP 應該讓使用者能將項目加入購物車。 這可以是單一項目,也可以同時是多個項目。 由於這是 MVP,項目數量以_重複出現_來表示。 如果使用者想加入 2 個 Orange,'Oranges' 會在輸入的可迭代物件中出現兩次。 如果購物車裡已經有這個項目,購物車中的數量應該增加 1。 如果這個項目對購物車來說是_新的_,就應該以數量 1 加入。
建立函式 add_item(<current_cart>, <items_to_add>),它接受一個購物車字典,以及任何類似陣列、要加入的項目可迭代物件作為引數。
它應該為使用者回傳一個新的或更新後的購物車字典。
>>> add_item({'Banana': 3, 'Apple': 2, 'Orange': 1},
('Apple', 'Apple', 'Orange', 'Apple', 'Banana'))
{'Banana': 4, 'Apple': 5, 'Orange': 2}
>>> add_item({'Banana': 3, 'Apple': 2, 'Orange': 1},
['Banana', 'Orange', 'Blueberries', 'Banana'])
{'Banana': 5, 'Apple': 2, 'Orange': 2, 'Blueberries': 1}
哎呀。 看來產品團隊開始陷入功能蔓延了。 他們想為 MVP 加入額外的功能。 應用程式現在必須藉由讀取使用者記事應用程式中的項目來建立購物車。 對使用者來說很方便,但對團隊來說稍微多了一些工作。
建立函式 read_notes(<notes>),它可以接受任何類似陣列的可迭代物件作為引數。
這個函式應該解析這些項目,並建立使用者的購物車字典。
每個項目都應該以數量 1 加入。
然後回傳新的使用者購物車。
>>> read_notes(('Banana','Apple', 'Orange'))
{'Banana': 1, 'Apple': 1, 'Orange': 1}
>>> read_notes(['Blueberries', 'Pear', 'Orange', 'Banana', 'Apple'])
{'Blueberries' : 1, 'Pear' : 1, 'Orange' : 1, 'Banana' : 1, 'Apple' : 1}
應用程式有一個「ideas」區段,裡面充滿了來自各國料理的現成食譜。 使用者可以選擇其中任何一份食譜,並自動將其所有食材加入購物車。 專案經理請你建立一種方法來編輯這些「ideas」食譜,因為內容團隊不斷更動食材和數量。
建立函式 update_recipes(<ideas>, <recipe_updates>),它接受一個「ideas」字典和一個食譜更新的可迭代物件作為引數。
這個函式應該回傳新的或更新後的「ideas」字典。
>>>update_recipes(
{'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}},
(('Banana Bread', {'Banana': 4, 'Walnuts': 2, 'Flour': 1, 'Butter': 1, 'Milk': 2, 'Eggs': 3}),)
)
...
{'Banana Bread': {'Banana': 4, 'Walnuts': 2, 'Flour': 1, 'Butter': 1, 'Milk': 2, 'Eggs': 3},
'Raspberry Pie': {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}}
>>> update_recipes(
{'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1},
'Pasta Primavera': {'Eggs': 1, 'Carrots': 1, 'Spinach': 2, 'Tomatoes': 3, 'Parmesan': 2, 'Milk': 1, 'Onion': 1}},
[('Raspberry Pie', {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2}),
('Pasta Primavera', {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1}),
('Blueberry Crumble', {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3})]
)
...
{'Banana Bread': {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
'Raspberry Pie': {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2},
'Pasta Primavera': {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1},
'Blueberry Crumble': {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3}}
使用者開始一個購物車之後,應用程式允許他們依字母順序排序項目。 這讓項目更容易找到,也能在出現資料輸入錯誤時有所幫助,例如資料庫裡同時有 'potatoes' 和 'Potato'。
建立函式 sort_entries(<cart>),它接受一個購物車字典作為引數,並回傳一個新的、依字母順序排序的購物車。
>>> sort_entries({'Banana': 3, 'Apple': 2, 'Orange': 1})
{'Apple': 2, 'Banana':3, 'Orange': 1}
應用程式需要將指定使用者的購物車送往商店備貨。 不過,商店裡的揀貨人員需要知道該項目位於哪個走道,以及該項目是否需要冷藏。 所以(相當任意地),「備貨購物車」需要依反向字母順序排序,並將項目數量與位置和冷藏資訊結合在一起。
建立函式 send_to_store(<cart>, <aisle_mapping>),它接受一個使用者購物車,以及一個包含各項目商店走道編號和是否需要冷藏的 True/False 的字典。
這個函式應該 return 一個合併後的「備貨購物車」,其中包含顧客所訂購每個項目的(數量、走道和冷藏)。
項目應該以_反向_字母順序出現。
>>> send_to_store({'Banana': 3, 'Apple': 2, 'Orange': 1, 'Milk': 2},
{'Banana': ['Aisle 5', False], 'Apple': ['Aisle 4', False], 'Orange': ['Aisle 4', False], 'Milk': ['Aisle 2', True]})
{'Orange': [1, 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True], 'Banana': [3, 'Aisle 5', False], 'Apple': [2, 'Aisle 4', False]}
應用程式不能只是無止境地接受顧客的訂單。 總有一天,商店的各種商品會用完。 所以你的 MVP 應用程式需要在使用者每次將訂單送往商店時更新商店庫存。 否則,顧客會訂購實際上沒有庫存的商品。
建立函式 update_store_inventory(<fulfillment_cart>, <store_inventory>),它接受一個「備貨購物車」和一個商店庫存。
這個函式應該依照「備貨購物車」中「訂購」的數量來扣減商店庫存,然後回傳更新後的商店庫存。
當某個商店項目的數量降為 0 時,該數量應該被替換為訊息 'Out of Stock'。
>>> update_store_inventory({'Orange': [1, 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True], 'Banana': [3, 'Aisle 5', False], 'Apple': [2, 'Aisle 4', False]},
{'Banana': [15, 'Aisle 5', False], 'Apple': [12, 'Aisle 4', False], 'Orange': [1, 'Aisle 4', False], 'Milk': [4, 'Aisle 2', True]})
{'Banana': [12, 'Aisle 5', False], 'Apple': [10, 'Aisle 4', False], 'Orange': ['Out of Stock', 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True]}