Dictionaries

Another data type in Python (and my personal favorite) is the dictionary. Similar to how an actual dictionary maps words to definitions, a Python dictionary maps keys to values.

Here's how we could make a mini slang dictionary using a Python dictionary:

slang_dictionary = {
   "yeet": "An expression of excitement or a verb signifying throwing something",
   "flex": "A verb, meaning to show off something",
   "slay": "A verb indicating someone did something very well in something",
   "sus": "Abbreviation for 'suspicious'",
   "salty": "Angry, upset, or bitter"
}

It's very easy to look up the value in a dictionary when we know the key, using another kind of bracket notation. Instead of specifying an index in the square brackets like we did for lists, we instead specify the key:

slang_dictionary["flex"]   # 'A verb, meaning to show off something'

You might be wondering why we don't just use a list or nested list, perhaps like this:

slang_dictionary = [
   ["yeet", "An expression of excitement or a verb signifying throwing something"],
   ["flex", "A verb, meaning to show off something"]
]

We could certainly find the definition of "flex" in that nested list, by either iterating through and checking values or by using a list method like find(). However, it would be a much slower operation, due to the differences in the ways Python lists and dictionaries are stored. If there were 10,000 sublists in that nested list, and the word we're looking for was at the end of the list, the computer would have to search through every single sublist. However, if there were 10,000 keys in a dictionary, and we looked up a word, the computer can find it immediately.

In conclusion: if you think that you are going to be frequently looking up something according to its key, a dictionary is typically the right data type to use.

Dictionary access

Let's dive more into how we can retrieve values from a dictionary (or dict, as it's formally known in Python).

Consider this dict that maps Spanish words to their English translations:

words = {
    "mรกs": "more",
    "otro": "other",
    "agua": "water"
}

We can retrieve a value by using bracket notation with the key inside the brackets, as shown above:

words["otro"]  # 'other'

However, we might sometimes have the key inside a variable. In that case, the variable name would go inside the brackets:

first_word = "agua"
words[first_word]  # 'water'

Basically, any expression can go inside those square brackets, as long as it eventually evaluates into a valid key.

If we ask for a key that's not there, we'll get a big old error.

words["pavo"]  # ๐Ÿšซ Error!

Fortunately, there's another approach if we're not sure about a key's existence. Python dicts have a get method that will retrieve a value if the key exists, and will otherwise default to whatever value you specify.

In this example, the default is a thinking face emoji:

words.get("pavo", "๐Ÿค”")  # '๐Ÿค”'

If we specify no default, then None is returned:

words.get("pavo") # None

Dictionary mutation

Just like lists, dictionaries are mutable data types. That means that we can continue modifying their contents after we initially create them, using various operators and methods.

A common way to use dictionaries is to start with an empty dict like so:

users = {}

And then add a value to it, using bracket notation:

users["pamelafox"] = "b3stp@ssEvErDontHackMe"

We can keep re-assigning a key to new values in the same way:

users["pamelafox"] = "EV3Nb3tt3Rp@ssw0rd!"

We can even use the += operator to add to an existing value, as long as it's a number or a string:

users["pamelafox"] += "itsLongerSoItsMoreSecure!!"

๐Ÿง  Check Your Understanding

What value would users["pamelafox"] retrieve now?

What's in a dict?

All of our example dicts so far have been using string keys and string values. However, it is possible to use any immutable type as a key - so the keys could actually be numbers! It's not nearly as common, but it is possible.

Consider this dict that maps years to the Pixar movie that came out that year:

pixar_by_year = {
   1995: "Toy Story",
   1998: "A Bug's Life",
   1999: "Toy Story 2",
   2001: "Monsters, Inc",
   2003: "Finding Nemo"
}

The values can be any type at all, including mutable types like lists.

Here's a dict for more recent Pixar films, where the values need to be lists since multiple films are released in some years:

pixar_by_year = {
   2017: ["Coco", "Cars 3"],
   2018: ["Incredibles 2"],
   2019: ["Toy Story 4"],
   2020: ["Soul", "Onward"]
}

We could mix-and-match, and have some values be strings and other values be lists, but it's usually better to stick with a consistent schema.

The values can even be nested dictionaries, making dicts an ideal way to store hierarchical data.

Here's a dict of my favorite spiders, with some properties of each one inside nested dicts:

spiders = {
  "smeringopus": {
      "name": "Pale Daddy Long-leg",
      "length": 7
  },
  "holocnemus pluchei": {
      "name": "Marbled cellar spider",
      "length": (5, 7)
  }
}

๐Ÿง  Check Your Understanding

What expression would retrieve the name "Marbled cellar spider" from the spiders dict?

Dictionary iteration

A Python dict is an iterable object, which means it can be iterated over using a for loop. In each iteration of the loop, the loop variable is assigned to the current key, and the loop body can choose what to do with that key.

For example, this loop prints out each value by doing dictionary a lookup with the key:

insects = {"spiders": 8, "centipedes": 100, "bees": 6}
for name in insects:
    print(insects[name])

What will be the order of the keys during the iteration? In younger versions of Python, the order was not defined, so the iteration might go through the keys in any order. However, in modern Python, the order is always according to when the keys were added to the dictionary.

In the example above, the order would be "spiders", then "centipedes", then "bees", so the loop would print 8, then 100, then 6.

Dictionary operations

Dictionaries support some of the same operators and functions as strings and lists.

Starting with this dict that maps US state codes to states:

states = {
    "CA": "California",
    "DE": "Delaware",
    "NY": "New York",
    "TX": "Texas",
    "WY": "Wyoming"
}

The len() function reports how many key/value pairs are the dict.

len(states)  # 5

The in operator reports whether or not a particular key is in a dict (it will not look for values):

"CA" in states  # True
"ZZ" in states  # False

There are also additional functions, operators, and methods for dicts that we won't dive into here. You can learn more in the Python dict documentation.

Exercise: Make a recipe

In the code editor below, create a dict to hold information on your favorite recipe. It should have keys for:

Once the dict is created, use bracket notation to pull value back out of the dict and print them out.

recipe = {
  # Put title key/value here - value should be a string
  # Put servings key/value here - value should be a number
  # Put ingredients key/value here - value should be a list
}

# Store the recipe's title in this variable
# by using bracket notation on the recipe variable
title = ''
print(title)

# Store the recipe's servings # in this variable
# by using bracket notation on the recipe variable
servings = -1
print(servings)

# Store the recipe's ingredients list in this variable
# by using bracket notation on the recipe variable
ingredients = []
print(ingredients)
โžก๏ธ Next up: Exercise: Dictionaries