Dictionaries¶
Goal: store values under names, look them up by name instead of by position, and count things with them.
Why this matters¶
A list is great when the order matters or when you just have a pile of things. But think about a phone book. You never want "the third number", you want "Ada's number". You could keep two lists, one of names and one of numbers, and hope they stay lined up. Python has a better tool for exactly this: a dictionary, which stores each value under a key of your choosing.
Creating and looking up¶
Write the pairs between curly braces. Each pair is a key, a colon, and a value:
phone_book = {
"Ada": "555-0101",
"Grace": "555-0142",
"Linus": "555-0199",
}
print(phone_book["Ada"])
print(phone_book["Linus"])
print(len(phone_book))
print(phone_book)
phone_book["Ada"] looks up the value stored under the key "Ada". The square brackets are the same ones you use to
index a list, but where a list takes a position number, a dictionary takes a key. The words in a real dictionary are
its keys, and the definitions are its values, which is where the name comes from.
Splitting the pairs over several lines, one per line, is optional. It just makes a long dictionary easier to read. The comma after the last pair is allowed and is a good habit, since it makes adding another line later painless.
len() gives the number of pairs. Keys are usually strings, but they can be numbers too. Each key appears only once:
if you store a second value under "Ada", it replaces the first.
Checking for a key¶
Looking up a key that does not exist is an error, KeyError. Two tools avoid it. in tells you whether a key is present,
and .get() looks up a key but hands back None instead of crashing when it is missing:
phone_book = {"Ada": "555-0101", "Grace": "555-0142"}
print("Ada" in phone_book)
print("Guido" in phone_book)
print(phone_book.get("Ada"))
print(phone_book.get("Guido"))
print(phone_book.get("Guido", "unknown"))
None is a special value that means nothing here. You met it in the last lesson as what .append() returns.
.get() takes an optional second value to return instead of None, which is often tidier than an if.
Note that in on a dictionary checks the keys, not the values. "555-0101" in phone_book is False.
Adding, changing, and removing¶
Like lists, dictionaries are mutable. Assigning to a key that is not there adds it. Assigning to a key that is there
replaces its value. del removes a pair:
phone_book = {"Ada": "555-0101", "Grace": "555-0142"}
phone_book["Linus"] = "555-0199"
print(phone_book)
phone_book["Ada"] = "555-0100"
print(phone_book)
del phone_book["Grace"]
print(phone_book)
{'Ada': '555-0101', 'Grace': '555-0142', 'Linus': '555-0199'}
{'Ada': '555-0100', 'Grace': '555-0142', 'Linus': '555-0199'}
{'Ada': '555-0100', 'Linus': '555-0199'}
There is no .append() for dictionaries, because there is no "end" to add to. You always say which key the value goes under.
{} is an empty dictionary, and the usual pattern is to start with one and fill it in a loop, as you will see shortly.
Looping over a dictionary¶
A for loop over a dictionary gives you each key in turn. To get the keys and values together, loop over .items()
and name two variables:
phone_book = {"Ada": "555-0101", "Grace": "555-0142", "Linus": "555-0199"}
for name in phone_book:
print(name)
print("---")
for name, number in phone_book.items():
print(f"{name}: {number}")
for name, number in phone_book.items(): unpacks each pair into two variables on every iteration. The names are yours
to choose, but the order is fixed: the key first, then the value. The pairs come out in the order they were added.
Splitting text into a list¶
For the counting examples that follow, you need one more string method. .split() chops a string into a list of words,
breaking at spaces. Give it a separator to break at something else instead:
sentence = "the quick brown fox"
words = sentence.split()
print(words)
print(len(words))
csv = "eggs,bread,apples"
items = csv.split(",")
print(items)
.split() is how you turn a line the user typed into pieces you can loop over. Remember the word counter in Module 3
that counted spaces and added one? len(sentence.split()) does the same job more honestly.
Counting with a dictionary¶
The most useful dictionary pattern is counting. The keys are the things being counted, and the values are how many times each has been seen:
text = "mississippi"
counts = {}
for letter in text:
if letter not in counts:
counts[letter] = 0
counts[letter] += 1
print(counts)
for letter, count in counts.items():
print(f"{letter} appears {count} times")
{'m': 1, 'i': 4, 's': 4, 'p': 2}
m appears 1 times
i appears 4 times
s appears 4 times
p appears 2 times
The two lines inside the loop are the heart of it. The first time a letter appears, it is not in counts yet, so
counts[letter] += 1 would be a KeyError. The if creates the entry with a zero first. After that, every visit
just adds one. This is the accumulator pattern with a dictionary of totals instead of a single total.
Swap text for sentence.split() and letter for word, and the same six lines count words instead of letters.
That is Exercise 3.
Try it¶
Make a dictionary of three friends and their birthdays. Print one birthday by name. Add a fourth friend.
Loop over the dictionary and print each line as Name was born on date. Then look up a name that is not there
using .get() with a default message.
Common mistakes¶
KeyError: 'Guido'
You looked up a key that is not in the dictionary. Check with in first, or use .get().
Watch for capitalization and spaces: "ada" and "Ada" are different keys.
ValueError: too many values to unpack (expected 2)
You wrote for name, number in phone_book: without .items(). Looping over a dictionary directly gives only the keys.
TypeError: unhashable type: 'list'
You tried to use a list as a key. Keys must be values that cannot change, such as strings and numbers. Lists can be dictionary values, just not keys.
KeyError inside a counting loop
The if key not in counts: counts[key] = 0 line is missing, so the first += 1 has nothing to add to.
The dictionary only has one entry
You are creating the dictionary inside the loop, so it resets every iteration. Move counts = {} above the for.
Exercises¶
- Capitals quiz. Make a dictionary of at least four countries and their capitals. Ask the user for a country and print its capital, or a polite message if you do not know it.
- Word lengths. Ask for a sentence and build a dictionary where each word is a key and its length is the value. Print each word and its length on its own line.
- Word frequency. Ask for a sentence and count how many times each word appears, ignoring case. Print the counts, then print the most common word. If two words tie, either is fine.
- Phone book. Write a menu program that loops until the user quits. The options are: add a name and number, look up a number by name, show everyone, and quit. Use a dictionary to store the entries.
Solution 1
Solution 2
sentence = input("Type a sentence: ")
lengths = {}
for word in sentence.split():
lengths[word] = len(word)
for word, length in lengths.items():
print(f"{word}: {length}")
No if is needed here, because a word that appears twice simply gets the same length stored twice.
Solution 3
sentence = input("Type a sentence: ")
counts = {}
for word in sentence.lower().split():
if word not in counts:
counts[word] = 0
counts[word] += 1
for word, count in counts.items():
print(f"{word}: {count}")
most_common = ""
highest = 0
for word, count in counts.items():
if count > highest:
most_common = word
highest = count
print(f"The most common word is '{most_common}', used {highest} times.")
The second loop is the "find the best" pattern from the longest-name exercise. highest starts at 0, so the first
word is always an improvement and becomes the answer until something beats it.
Solution 4
phone_book = {}
while True:
print()
print("1. Add a number")
print("2. Look up a number")
print("3. Show everyone")
print("4. Quit")
choice = input("Choose: ")
if choice == "1":
name = input("Name: ")
number = input("Number: ")
phone_book[name] = number
print(f"Saved {name}.")
elif choice == "2":
name = input("Name: ")
if name in phone_book:
print(f"{name}: {phone_book[name]}")
else:
print(f"{name} is not in the phone book.")
elif choice == "3":
if len(phone_book) == 0:
print("The phone book is empty.")
for name, number in phone_book.items():
print(f"{name}: {number}")
elif choice == "4":
print("Goodbye.")
break
else:
print("Please choose 1, 2, 3, or 4.")
This is the biggest program in the course so far, and every piece of it is something you have already learned.
The empty print() puts a blank line before each menu to keep the output readable.
Summary¶
- A dictionary maps keys to values:
book = {"Ada": "555-0101"}. Look up withbook["Ada"]. key in bookchecks for a key.book.get(key, default)looks up without crashing.- Assigning to a key adds or replaces.
del book[key]removes. for key, value in book.items():loops over pairs.text.split()turns a string into a list of words.- To count things: start with
{}, and inside the loop create the key with 0 if it is missing, then add 1.
Module 4 complete¶
Lists and dictionaries are the two containers you will use in nearly every program from now on. Module 5 teaches functions, which let you name a block of code and reuse it, so your programs stop being one long script.