Python for Programmers: Dictionary Methods
Welcome to the Dictionary Methods lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
Dictionaries show up everywhere in Python. Many dictionary methods are shorthands for common patterns, so it's good to know them.
The next example loops over a list of words. It builds a dictionary mapping the words to the list index where we first saw them. When a value occurs multiple times, we only store the first index that contained the value.
>
first_indexes = {}words = ["apple", "banana", "apple"]for index, word in enumerate(words):if word not in first_indexes:first_indexes[word] = indexfirst_indexesResult:
{'apple': 0, 'banana': 1}That solution works, but we can use dictionaries'
.setdefault(key, default)method to avoid theifentirely. It sets a dictionary key, but only if the key doesn't already exist.>
firstIndexes = {}words = ["apple", "banana", "apple"]for index, word in enumerate(words):firstIndexes.setdefault(word, index)firstIndexesResult:
{'apple': 0, 'banana': 1}.setdefaultis often used when dealing with configuration data. Instead of calling.getwith a default, some codebases call.setdefaultwith the default. This lets us set up the entire configuration dictionary in one place.>
coffee_config = {"cream": True,}coffee_config.setdefault("cream", False)coffee_config.setdefault("sugar", False)coffee_config.setdefault("temperature", 93) # Celsiuscoffee_configResult:
{'cream': True, 'sugar': False, 'temperature': 93}Sometimes we want to get a key's value and also remove it from the dictionary at the same time. The
.popmethod does that, by analogy to the.popmethod on lists.>
cat_ages = {"Ms. Fluff": 4,"Keanu": 2}cat_ages.pop("Ms. Fluff")Result:
4
>
cat_ages = {"Ms. Fluff": 4,"Keanu": 2}cat_ages.pop("Ms. Fluff")cat_agesResult:
{'Keanu': 2}.popraises aKeyErrorwhen the key doesn't exist.>
cat_ages = {"Ms. Fluff": 4,"Keanu": 2}age = cat_ages.pop("Wilford")age, cat_agesResult:
KeyError: 'Wilford'
The
.popmethod takes a default value as its optional second argument. If the key doesn't exist, it returns the default value. The dictionary isn't changed, since the key never existed.>
cat_ages = {"Ms. Fluff": 4,"Keanu": 2}age1 = cat_ages.pop("Ms. Fluff", 0)age2 = cat_ages.pop("Keanu", 0)age3 = cat_ages.pop("Wilford", 0)age1 + age2 + age3Result:
6
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
cat_agesResult:
{} Finally,
dict_1.update(dict_2)modifiesdict_1by adding all ofdict_2's entries. But it doesn't modifydict_2.We can think of this as doing
dict_1[key] = dict_2[key]for all keys indict_2. When both dicts have a key, the value fromdict_2"wins".>
dict_1 = {"a": 1,"b": 2,}dict_2 = {"b": 3,"c": 4,}dict_1.update(dict_2)dict_1Result:
{'a': 1, 'b': 3, 'c': 4}- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
dict_2Result:
{'b': 3, 'c': 4} We previously saw dictionary merging, for example with
dict_1 = dict_1 | dict_2. Using.updateis different in a couple of ways. Both stem from the fact thatdict_1 | dict_2builds an entirely new dictionary, whereas.updatemodifies an existing dictionary.First, this means that
dict_1 | dict_2is generally slower, since it has to build an entire dictionary from scratch. This is especially true whendict_1is large, since all of those entries have to be copied into the new dict.Second, it's possible that many parts of the system hold a reference to
dict_1. If we calldict_1.update(...), all of those references will see the change, since they all refer to the same dictionary object in memory. But if we dodict_1 = dict_1 | dict_2, we're only replacing the local variabledict_1. Other parts of the system may still have references to the olddict_1.The examples below show that difference.
>
amir = {"name": "Amir","coffee_config": {"cream": True,},}# We destructively update Amir's coffee_config with a new key.amir["coffee_config"].update({"cream": False,})amir["coffee_config"]Result:
{'cream': False}>
amir = {"name": "Amir","coffee_config": {"cream": True,},}# We non-destructively build a new coffee_config dict.coffee_config = amir["coffee_config"] | {"cream": False}amir["coffee_config"]Result:
{'cream': True}Here's a code problem:
Write a function,
update_default, that takes two dictionaries as arguments. It updates the first dictionary with items from the second dictionary. However, when a key already exists in the first dictionary,update_defaultshouldn't change it.Two hints:
- There are many ways to solve this, but we recommend using
setdefaultinside of a loop. - You can use
dict.items()to loop through a dictionary's key-value pairs.
def update_default(dict_1, dict_2):for key, value in dict_2.items():dict_1.setdefault(key, value)dict_1 = {"a": 1}update_default(dict_1, {"a": 2, "b": 3})assert dict_1 == {"a": 1, "b": 3}dict_2 = {"a": 1, "b": 2, "c": 3}update_default(dict_2, {"a": 4, "e": 5, "f": 6})assert dict_2 == {"a": 1, "b": 2, "c": 3, "e": 5, "f": 6}- Goal:
No errors.
- Yours:
No errors.
- There are many ways to solve this, but we recommend using