Python for Programmers: Building New Dictionaries
Welcome to the Building New Dictionaries lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
We can create new dicts with the literal syntax,
{...}, but there are also many other ways. This lesson covers four other ways to build dictionaries.First, we can call the
dictbuilt-in as a function. The simplest way is to pass in an existing dictionary, which copies it. Changing the copy doesn't affect the original (and vice-versa).>
original_data = {"a": 1,"b": 2}other_data = dict(original_data)other_data["c"] = 3- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
other_dataResult:
{'a': 1, 'b': 2, 'c': 3} - Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
original_dataResult:
{'a': 1, 'b': 2} Calling
dict(...)copies over the key-value pairs, but it doesn't copy the keys and values themselves. For example, if one of the dict values is a list, then the new dict references that same list. When we mutate the list, that change is visible from both dictionaries.>
original_data = {"log": [2, 3]}copied_data = dict(original_data)copied_data["log"].append(4)original_data["log"]Result:
[2, 3, 4]
The term for this is "shallow copy": we only copied the dict itself, not its contents. It would be a "deep copy" if the new dict contained new copies of any lists/dicts/tuples inside the original dict, and those contained new copies of any data inside of them. All of the techniques shown in this lesson make shallow copies.
The second way to build a dictionary is to call
dictwith a list of key-value pairs stored as tuples. (This works with any iterable, not just lists, but iterables are covered elsewhere in the course.)>
amir = dict([("name", "Amir"), ("age", 36)])amirResult:
{'name': 'Amir', 'age': 36}That list corresponds to the
.itemsdict method, which returns the dict's items in a similar form: an iterable of key-value tuples. In the next example, we calllist(...)to see its actual contents.>
user = {"name": "Amir","age": 36,}list(user.items())Result:
The third way is to combine two existing dicts with
dict1 | dict2. This merges their items.>
name_info = {"name": "Amir"}age_info = {"age": 36}person = name_info | age_infopersonResult:
{'name': 'Amir', 'age': 36}The entries are merged from left to right. When both dictionaries have the same key, the right dictionary "wins".
>
user_data = {"name": "Betty","mailing_list": True}updates = {"mailing_list": False}user_data = user_data | updatesuser_data["mailing_list"]Result:
False
Finally, the fourth way to create a new dict is by using the
**operator in a literal. Inside of a dict literal,**other_dictmeans "include all the items ofother_dictwhen creating this dict". This is sometimes called "expanding a dict into a dict literal".>
amir_age = {"Amir": 36}user_ages = {**amir_age,"Betty": 41,}user_agesResult:
{'Amir': 36, 'Betty': 41}Above, we used
**with a variable:**amir_age. But we can use**with any expression, not just variables. In the next example, we use it to include a ternary expression that returns one of two different literal dicts.>
def build_user(name, age=None):return {"name": name,**({} if age is None else {"age": age}),}- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
build_user("Amir")Result:
{'name': 'Amir'} - Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
build_user("Amir", age=36)Result:
{'name': 'Amir', 'age': 36} This lesson covered four different ways to create dictionaries:
- dict(some_dict)
- dict(list_of_keys_and_values)
- Merge dictionaries with
dict1 | dict2. - Merge dictionaries into a literal with
{..., **some_dict, ...}.
All of these ways are "non-destructive": they build new dictionaries, but they don't modify any existing dictionaries. That makes code easier to think about. We don't have to worry about whether
dict1 | dict2modified either of the original dicts.