Execute Program

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 dict built-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_data
    Result:
    {'a': 1, 'b': 2, 'c': 3}Pass Icon
  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    original_data
    Result:
    {'a': 1, 'b': 2}Pass Icon
  • 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]Pass Icon
  • 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 dict with 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)])
    amir
    Result:
    {'name': 'Amir', 'age': 36}Pass Icon
  • That list corresponds to the .items dict method, which returns the dict's items in a similar form: an iterable of key-value tuples. In the next example, we call list(...) 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_info
    person
    Result:
    {'name': 'Amir', 'age': 36}Pass Icon
  • 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 | updates
    user_data["mailing_list"]
    Result:
    FalsePass Icon
  • Finally, the fourth way to create a new dict is by using the ** operator in a literal. Inside of a dict literal, **other_dict means "include all the items of other_dict when 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_ages
    Result:
    {'Amir': 36, 'Betty': 41}Pass Icon
  • 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'}Pass Icon
  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    build_user("Amir", age=36)
    Result:
    {'name': 'Amir', 'age': 36}Pass Icon
  • 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 | dict2 modified either of the original dicts.