Back to Article
PE100-10: Dictionaries
Download Notebook

PE100-10: Dictionaries

Dictionaries are, conceptually, a special type of list. A list has an order to it. Elements are placed into a list in a particular order. Removing and inserting items changes the order in a well understood way. Because of this, yoiu can always access a list by looking into it at a specific integer index. None of this is possible with a dictionary. Instead, dictionaries have a better trick: all access is by searching.

Python’s dictionaries store each of their elements as a pair of things, a key and a value. The key is the thing that can be searched for, and the value is the information that will be retured when that element is read.

An example will help:

In [4]:
favorite_food = { "Alice" : "Apple Pie", \
                 "Bob" : "Ice Cream",\
                 "Charlie" : "Pizza" }
print(favorite_food["Bob"])
                 
Ice Cream

Let’s take that apart and see how it works.

  1. We have the creation of the dictionary itself. We create a dictionary literal much like we do a list, only here we use curly brackets instead of square brackets.

  2. We have key:value pairs. The keys we’re using are all strings (people’s names, in fact) but they could just as well be numbers. The values are also strings, but they can be anything we want. These keys and values are separated by colons (:).

  3. Between each of the key:value pairs there is a comma.

  4. We see how to look up information in a dictionary. It looks like indexing into a list to extract a particular element, except in this case we don’t give a positional index number but rather we give it a key to look up.

When you think about it, looking for Bob’s favorite food by using favorite_food["Bob"] is a pretty powerful tool. Rather than having to specify where to get something from, we can just specify what to get. This is why you’ll occasionally see dictionaries refered to as “Content Addressable Memory”. It’s nice to just get the data we want without having to step through every element of a list looking for it. It’s also faster: Python’s dictionaries use clever indexing so they can straight to what you’re looking for.

Dictionaries get their name, by the way, from real-world physical dictionaries. Suppose you have Webster’s 9th New Collegiate Dictionary in front of you. There are a lot of keys in there - each one of those words in alphabetical order is a key. There’s not really any way to look up something by page number alone - there’s no algorithm to tell me what page the definition for brisance is on. There’s no way to look up a word by knowing which word number it is. If brisance is the 8000th word in the dictionary, that knowledge does me no good. On the other hand, there is an algorithm for finding that definition by looking up the key word. I go to the “B”s, look for the “Br” part, and so forth until I find brisance. I can only look up things by key, not by position.

One of the great things about Python is its flexibility with data types. Lists can contain any data type. You can have lists of tuples of lists of strings if you want to. Dictionaries are similarly versatile. You can have dictionaries that contain, say, lists:

In [6]:
family_info = { 'ages' : [6,8,36,38],\
               'names' : ['Jane', 'John', 'Alice', 'Bob'] }

print(family_info["names"])
['Jane', 'John', 'Alice', 'Bob']

You can even have dictionaries of dictionaries. They’re quite useful, in fact.

In [9]:
fast_food = { "McAwful" : { "address" : "1012 Western Blvd",\
                            "sanitation" : 92} ,\
            "Davids" : { "address" : "201 S Fayetteville St",\
                         "sanitation" : 99.5 } }

print (fast_food["Davids"]["sanitation"])
99.5

Dictionaries give us the beginnings of a database. It’s not as powerful as a “real” database, but it’s good enough for a lot of things. Of course, a dictionary is like any iother variable: it only lasts as long as your program is running. You would have to combine a dictionary with some file access to have any permanent storage.

What happens if we try to look up a key:value pair, and the key isn’t in the dictionary? Let’s see!

In [10]:
print(fast_food["Ruth's Chris"])
KeyError: "Ruth's Chris"

Yeah, we expected that by now, didn’t we? It threw a “KeyError” exception. What should we do about this? We could always wrap the access up in a try/except structure to catch the KeyError, but this is such a common problem that Python gives us a friendlier way to do it: the in operator.

Remember using in to see if something was in a string? This is philosophically similar. Let’s try it:

In [11]:
if "Ruth's Chris" in fast_food:
    print("Surprised to see such an expensive place here!")
else:
    print("that's a relief, actually.")
that's a relief, actually.

Adding to a dictionary is even easier than adding to a list. All you do is just act like the key was already there and assign it a value:

In [15]:
print(favorite_food)
print()
favorite_food["Dan"] = 'Fish'
print("Now we have:")
print(favorite_food)
{'Alice': 'Apple Pie', 'Bob': 'Ice Cream', 'Charlie': 'Pizza', 'Dan': 'Fish'}

Now we have:
{'Alice': 'Apple Pie', 'Bob': 'Ice Cream', 'Charlie': 'Pizza', 'Dan': 'Fish'}

What happens if we try to overwrite some data?

In [16]:
favorite_food["Charlie"] = "Soup"
print(favorite_food)
{'Alice': 'Apple Pie', 'Bob': 'Ice Cream', 'Charlie': 'Soup', 'Dan': 'Fish'}

We can change what is stored in the “value” part of the key:value pair any time we want. We can’t change the key, though. At least, we can’t change it directly. We can always delete the existing key:value pair and replace it with a new one. Let’s say Charlie really wants to be known as Chuck. He has his reasons. So let’s fix the favorite_food dictionary:

In [17]:
munchie = favorite_food["Charlie"]
del favorite_food["Charlie"]
favorite_food["Chuck"]=munchie
print(favorite_food)

What we did to accomplish that was 1. Look up Charlie’s favorite food and save that value. 2. use the built-in del operator to remove Charlie as a key and whatever value was associated with him. 3. Insert a new key:value pair whose key is “Chuck” and whose value is whatever we looked up before.

Since every other Python data type that holds more than one thing can work with the built-in len() function, it stands to reason that dictionaries can, too. And as you would imagine, len() returns the number of entries in the dictionary.

In [19]:
len(favorite_food)
4

Looping and Iteration


A dictionary is another type of iterable. This means we can write loops that traverse the entire dictionary, start to finish, and do something useful.

In [20]:
for key in favorite_food:
    print(key)
Alice
Bob
Dan
Chuck

Notice that a traversal of a dictionary retrieves the keys. If you want to retrieve the values, just use the keys to look up the values.

for key in favorite_food: print(favorite_food[key])