Python 3.4Free video13 minLesson 4 of 6 in Module 3
Dictionaries
Map keys to values: counting, grouping, lookup.
Free sample. Everything in this module opens with a free account.
Watch or read the lesson: Dictionaries
01Finding prices
Go back to the restaurant receipt from the for loops lesson. The menu was stored in two separate lists: one holding the item names, and the other holding their prices. The price of each item was stored at the same index as its name.
Now suppose you want the price of Soup. How would you get it? First, items.index("Soup") finds the position of "Soup" in the items list, which is index 2. Then you use that index to look up the matching price, and prices[2] is 6.0. Here are both steps in one cell:
items = ["Pasta", "Salad", "Soup"]
prices = [12.50, 8.25, 6.00]
prices[items.index("Soup")]
6.0
That works.
The problem with two lists
But there is a problem with this approach. Think about what Python has to do when you call index(). It starts with the first item in the list and checks whether it is "Soup". If not, it moves to the next one, and it keeps checking until it finds a match.
With just three items, that is hardly a problem. But what if the menu contains hundreds of items, or thousands? The search could take longer.
There is another problem. You have to make sure both lists stay in exactly the same order. If you accidentally sort one list without sorting the other, the names and prices no longer match.
So wouldn't it be better to store each item together with its price, and then look up the price directly using the item's name?
A dictionary
That is exactly what a dictionaryKey termA collection of key value pairs, looked up by key: {"Pasta": 12.50, "Salad": 8.25}. Its type is dict. lets you do. Here is the same menu again, but this time as a dictionary. You write the item name, followed by a colon, followed by its price, and you separate each entry with a comma. All of this goes inside curly brackets. So Pasta has a price of 12.50, Salad 8.25, and Soup 6.00:
menu = {"Pasta": 12.50, "Salad": 8.25, "Soup": 6.00}
menu["Soup"]
6.0
menu["Soup"] gives 6.0. There is no need to search through a list of names, no need to find an index, and no need to keep two separate lists in step. You simply provide the item's name and get its price.
So how does that work, and what else can you do with dictionaries? That is what this lesson explores. You will learn how to create dictionaries, look up values, add and remove entries, and loop through their contents.
02Keys, values and hashing
Start with the basics. A dictionary stores data as key-value pairs. That is an important term. In the menu, the name "Pasta" is a keyKey termWhat a dictionary looks a value up by, such as "Pasta" in the menu. Each key appears once, and must be hashable., and 12.50 is the valueKey termWhat a dictionary stores for each key, such as 12.50 for "Pasta". Values can be anything, including lists and dictionaries. associated with that key. Similarly, "Salad" is another key, and 8.25 is its value.
So every entry has two parts: a key, which you use to identify something, and a value, which holds the information associated with it. When you display the menu, Python shows all three pairs:
menu
{'Pasta': 12.5, 'Salad': 8.25, 'Soup': 6.0}
Reading a value
How do you read a value from a dictionary? The syntax looks familiar: you use square brackets, just as you did with lists. But there is an important difference. With a list, you put an index inside the brackets. With a dictionary, you put a key:
menu["Salad"]
8.25
Notice that you are not asking for the second element. 8.25 is the value associated with the key "Salad".
How the lookup is fast
Here is an interesting question. How does Python find that value without searching through every key?
Remember hashing from the sets lesson? Dictionaries use the same basic idea. When you add a key to a dictionary, Python computes a hash from that key, and uses that hash to help decide where to store the entry internally. Then, when you look up that key again, Python computes its hash again and uses it to find the matching entry efficiently.
On average, a dictionary lookup takes roughly constant time. That means a lookup does not normally get much slower just because the dictionary contains more entries. That is one of the reasons dictionaries are so useful.
03Missing keys
What happens if you try to look up something that is not in the dictionary?
menu["Pizza"]
KeyError: 'Pizza'
Python raises a KeyError, because "Pizza" is not one of the keys in the dictionary.
When you see a KeyError, the first thing to check is whether the key you are trying to access actually exists. Maybe it was misspelled. Maybe it has not been added yet. Or maybe you are using the wrong key altogether.
Fortunately, Python gives you a couple of ways to handle missing keys.
The in operator
The first is the membership operator, in. You have already used it with lists and sets, and it works with dictionaries too:
"Pizza" in menu
False
This returns False, because "Pizza" is not a key in the dictionary.
Now a quick question. You know that Pasta costs 12.50. So what happens if you write 12.5 in menu? Will Python return True because that price exists, or False? Think it through before reading on.
I have a guess. Show meHide the answer
12.5 in menu
False
The answer is False. When you use in directly with a dictionary, Python checks the keys, not the values. And 12.5 is a value in the menu, not a key.
If you actually want to check the values, use the values() method:
12.5 in menu.values()
True
This returns True, because 12.5 is one of the prices.
get
There is another way to read a dictionary value, and it is especially useful when the key might not exist. It is called get():
print(menu.get("Pizza"))
None
Instead of raising a KeyError, get() returns None. You already know that None is Python's special value for representing the absence of a value.
get() also lets you provide a default value:
menu.get("Pizza", 0.0)
0.0
Here you are telling Python: try to find the value for "Pizza", but if "Pizza" does not exist, give me 0.0 instead. That is why the result is 0.0.
If the key does exist, the default is not used:
menu.get("Soup", 0.0)
6.0
This still gives 6.0, because "Soup" is in the dictionary.
Square brackets or get
So when should you use square brackets, and when should you use get()? Use square brackets when the key is expected to exist. If it is missing, the KeyError helps you catch a mistake. But when a key might legitimately be missing, get() is often more convenient, especially when you have a sensible default value.
04Adding, updating and removing
Now that you know how to read values, here is how to change a dictionary. Dictionaries are mutable, just like lists and regular sets. That means you can add, update and remove entries after creating the dictionary.
Start by adding a new item to the menu. Suppose you want to add Bread for $3.75. You write menu["Bread"] = 3.75:
menu["Bread"] = 3.75
menu
{'Pasta': 12.5, 'Salad': 8.25, 'Soup': 6.0, 'Bread': 3.75}
Now the dictionary contains four items:
len(menu)
4
Updating an existing key
Here is something interesting. What if you use the same syntax with a key that already exists?
menu["Soup"] = 6.50
Python does not add another Soup entry. Instead, it updates the existing value of "Soup". This is important: a dictionary cannot contain duplicate keys as separate entries. Each key identifies one value. If you assign a value to a new key, Python adds an entry. If you assign a value to an existing key, Python replaces the old value.
Insertion order
Now a prediction. You originally created the menu with Pasta, Salad and Soup. Then you added Bread. And finally, you updated the price of Soup. So what order will the keys appear in now? Will Soup move to the end because you updated it, or will it stay in its original position? You can check with list(menu), which gives the keys as a list. Think it through before reading on.
I have a guess. Show meHide the answer
list(menu)
['Pasta', 'Salad', 'Soup', 'Bread']
The keys are Pasta, Salad, Soup and Bread. Soup has not moved, and Bread is at the end. Why? Because dictionaries preserve insertion orderKey termThe order keys were first added to a dictionary; updating a value preserves its position.: keys appear in the order they were first added. Updating the value of an existing key does not change its position. Displaying the whole dictionary shows the same order, along with Soup's new price:
menu
{'Pasta': 12.5, 'Salad': 8.25, 'Soup': 6.5, 'Bread': 3.75}
This is different from sets, which do not guarantee any order, as you saw in the previous lesson.
pop
What if you want to remove something from the menu? You use pop(). To remove Salad, you write menu.pop("Salad"):
menu.pop("Salad")
8.25
Python removes the Salad entry, and it also returns the value that was associated with it, so you get 8.25. Now the menu contains Pasta, Soup and Bread:
menu
{'Pasta': 12.5, 'Soup': 6.5, 'Bread': 3.75}
05Views and dictionary loops
Now restore the original menu, with Pasta, Salad and Soup, so you can see how to work with all the entries in a dictionary. Python provides three useful methods for this: keys(), values() and items().
Start with keys():
menu = {"Pasta": 12.50, "Salad": 8.25, "Soup": 6.00}
menu.keys()
dict_keys(['Pasta', 'Salad', 'Soup'])
Python gives you a view of the dictionary's keys. In this example, that is Pasta, Salad and Soup.
You have already met values(). It gives you a view of the dictionary's values, which here are the prices:
menu.values()
dict_values([12.5, 8.25, 6.0])
items
The third method is items(), and it is especially useful when you are working with loops. menu.items() gives you a view of the dictionary's key-value pairs:
menu.items()
dict_items([('Pasta', 12.5), ('Salad', 8.25), ('Soup', 6.0)])
When you iterate over it, each entry is represented as a tuple. The key comes first, and the value comes second. So the first pair contains 'Pasta' and 12.5, and so on.
Looping over items
Now write a for loop. Instead of looping over a list of items and a list of prices separately, loop directly over menu.items(), and unpack each pair into two variables, item and price:
for item, price in menu.items():
print(f"{item:<10} {price:>6.2f}")
Pasta 12.50
Salad 8.25
Soup 6.00
On the first iteration, item is 'Pasta' and price is 12.5. On the second iteration, item is 'Salad' and price is its price, and so on. Inside the loop, an f-string prints each item and its price.
Looping over the dictionary itself
Here is another detail. If you loop directly over a dictionary, without calling items() or keys(), Python gives you the keys:
for item in menu:
print(item)
Pasta
Salad
Soup
06Hashable keys
Now, what kinds of objects can you use as dictionary keys? In the sets lesson, you saw that set elements need to be hashable. Dictionary keys have the same requirement: they must be hashable too.
Here is an example. Suppose you are storing city names by their GPS coordinates. You might want to use the coordinates as the key, and the city name as the value. What happens if you try using a list containing the latitude and longitude as a key?
{[40.7128, -74.006]: "New York"}
TypeError: unhashable type: 'list'
Python raises a TypeError, telling you that a list is unhashable. You know why: lists are mutable.
But if you represent the same coordinate as a tuple containing two floats, it works, because a tuple is hashable. So you can use it as a dictionary key, and when you look up that coordinate, Python gives you the matching city name:
cities = {(40.7128, -74.006): "New York"}
cities[(40.7128, -74.006)]
'New York'
Values have no such restriction
Here is an important distinction. Dictionary keys need to be hashable, but dictionary values do not have that restriction. A value can be a number, a string, a list, or even another dictionary.
07Counting and Counter
Now to something especially useful: counting. Imagine six people voting for their favorite drink. Their votes are tea, coffee, tea, juice, tea and coffee. You want to find out how many votes each drink received.
A dictionary is a natural fit. Each drink name becomes a key, and its vote count becomes the value.
The counting rule
You start with an empty dictionary called counts. Then you loop through the votes, and for each vote you write counts[vote] = counts.get(vote, 0) + 1.
See how get() is used here. If the drink is not in counts yet, get() gives you zero, so you store zero plus one. You can see that on its own before any loop runs:
votes = ["tea", "coffee", "tea", "juice", "tea", "coffee"]
counts = {}
counts.get("tea", 0)
0
counts["tea"] = counts.get("tea", 0) + 1
counts
{'tea': 1}
And if the drink is already there, get() gives you its current count, and you add one to it:
counts.get("tea", 0)
1
counts["tea"] = counts.get("tea", 0) + 1
counts
{'tea': 2}
Following the votes
Now follow the first few votes through the loop. The first vote is tea. Tea is not a key yet, so its count becomes 1. Next comes coffee, which also starts at 1. Then tea appears again. This time get() finds 1, so tea's count becomes 2. By the end of the loop, tea has three votes, coffee has two, and juice has one:
counts = {}
for vote in votes:
counts[vote] = counts.get(vote, 0) + 1
counts
{'tea': 3, 'coffee': 2, 'juice': 1}
Counter
Counting is so common that Python provides a tool for it. It is called Counter, and it comes from the collections module. You import it, and then call Counter(votes):
from collections import Counter
Counter(votes)
Counter({'tea': 3, 'coffee': 2, 'juice': 1})
It gives you the same three counts. And if you want the most popular drink, you can use most_common(1):
Counter(votes).most_common(1)
[('tea', 3)]
That gives you tea, with three votes.
08Recap and challenge
This lesson started with a restaurant menu stored in two separate lists, where finding a price meant searching for the item name and then using its index to read the matching price. Then you replaced those lists with a dictionary, and learned how a dictionary stores key-value pairs.
You saw how hashing makes key lookups efficient on average, how square brackets retrieve values, and how get() helps you handle missing keys. Then you learned how to add, update and remove entries, and that dictionaries preserve insertion order. You also explored the keys(), values() and items() methods, and used tuple unpacking in a loop. Finally, you used a dictionary to count votes, and saw how Counter does the same job for you.
Your challenge
Return to the restaurant menu, with its three items: Pasta, Salad and Soup. Suppose six orders come in: Pasta, Soup, Pasta, Salad, Pasta and Soup.
menu = {"Pasta": 12.50, "Salad": 8.25, "Soup": 6.00}
orders = ["Pasta", "Soup", "Pasta", "Salad", "Pasta", "Soup"]
- Count how many times each item was ordered, using a dictionary to store the counts.
- Calculate the total value of all six orders. For each order, look up the item's price in the menu and add it to a running total.
- Finally, use
Counterto check whether your manual counts are correct.
In the module project, you will use exactly this pattern to count words in product reviews. But a review is one long piece of text, not a list of words, so first you need to learn how to work with strings. That is what the next lesson explores.
Key terms: Dictionaries
The words this lesson introduces, each in one line. The module’s glossary collects them all, and the AI glossary has every term across the courses.
- Counter
- A dictionary that counts; a missing key counts zero.
Counter(votes).most_common(1)gives[('tea', 3)]. Fromcollections. - defaultdict
- A dictionary that creates a missing key's value when the key is read:
defaultdict(list)creates[]. Fromcollections. - dictionary
- A collection of key value pairs, looked up by key:
{"Pasta": 12.50, "Salad": 8.25}. Its type isdict. - insertion order
- The order keys were first added to a dictionary; updating a value preserves its position.
- key
- What a dictionary looks a value up by, such as
"Pasta"in the menu. Each key appears once, and must be hashable. - key value pair
- One entry of a dictionary: a key and its value, written
"Pasta": 12.50. - nested dictionary
- A dictionary whose values are dictionaries:
cafe["drinks"]["Juice"]. - value
- What a dictionary stores for each key, such as
12.50for"Pasta". Values can be anything, including lists and dictionaries.
Quiz: Dictionaries
Your first pick on each question is the one that counts. Getting one wrong here is how the lesson sticks.